diff options
Diffstat (limited to 'drivers')
394 files changed, 10359 insertions, 7971 deletions
diff --git a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile index 2fa9a8bf48a..d006c9f168d 100644 --- a/drivers/acorn/char/Makefile +++ b/drivers/acorn/char/Makefile @@ -2,5 +2,4 @@ # Makefile for the acorn character device drivers. # -obj-$(CONFIG_ARCH_ACORN) += i2c.o pcf8583.o obj-$(CONFIG_L7200_KEYB) += defkeymap-l7200.o keyb_l7200.o diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c deleted file mode 100644 index d276fd14d63..00000000000 --- a/drivers/acorn/char/i2c.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * linux/drivers/acorn/char/i2c.c - * - * Copyright (C) 2000 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. - * - * ARM IOC/IOMD i2c driver. - * - * On Acorn machines, the following i2c devices are on the bus: - * - PCF8583 real time clock & static RAM - */ -#include <linux/capability.h> -#include <linux/init.h> -#include <linux/time.h> -#include <linux/miscdevice.h> -#include <linux/rtc.h> -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> -#include <linux/fs.h> - -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/hardware/ioc.h> -#include <asm/system.h> -#include <asm/uaccess.h> - -#include "pcf8583.h" - -extern int (*set_rtc)(void); - -static struct i2c_client *rtc_client; -static const unsigned char days_in_mon[] = - { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - -#define CMOS_CHECKSUM (63) - -/* - * Acorn machines store the year in the static RAM at - * location 128. - */ -#define CMOS_YEAR (64 + 128) - -static inline int rtc_command(int cmd, void *data) -{ - int ret = -EIO; - - if (rtc_client) - ret = rtc_client->driver->command(rtc_client, cmd, data); - - return ret; -} - -/* - * Update the century + year bytes in the CMOS RAM, ensuring - * that the check byte is correctly adjusted for the change. - */ -static int rtc_update_year(unsigned int new_year) -{ - unsigned char yr[2], chk; - struct mem cmos_year = { CMOS_YEAR, sizeof(yr), yr }; - struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk }; - int ret; - - ret = rtc_command(MEM_READ, &cmos_check); - if (ret) - goto out; - ret = rtc_command(MEM_READ, &cmos_year); - if (ret) - goto out; - - chk -= yr[1] + yr[0]; - - yr[1] = new_year / 100; - yr[0] = new_year % 100; - - chk += yr[1] + yr[0]; - - ret = rtc_command(MEM_WRITE, &cmos_year); - if (ret == 0) - ret = rtc_command(MEM_WRITE, &cmos_check); - out: - return ret; -} - -/* - * Read the current RTC time and date, and update xtime. - */ -static void get_rtc_time(struct rtc_tm *rtctm, unsigned int *year) -{ - unsigned char ctrl, yr[2]; - struct mem rtcmem = { CMOS_YEAR, sizeof(yr), yr }; - int real_year, year_offset; - - /* - * Ensure that the RTC is running. - */ - rtc_command(RTC_GETCTRL, &ctrl); - if (ctrl & 0xc0) { - unsigned char new_ctrl = ctrl & ~0xc0; - - printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n", - ctrl, new_ctrl); - - rtc_command(RTC_SETCTRL, &new_ctrl); - } - - if (rtc_command(RTC_GETDATETIME, rtctm) || - rtc_command(MEM_READ, &rtcmem)) - return; - - real_year = yr[0]; - - /* - * The RTC year holds the LSB two bits of the current - * year, which should reflect the LSB two bits of the - * CMOS copy of the year. Any difference indicates - * that we have to correct the CMOS version. - */ - year_offset = rtctm->year_off - (real_year & 3); - if (year_offset < 0) - /* - * RTC year wrapped. Adjust it appropriately. - */ - year_offset += 4; - - *year = real_year + year_offset + yr[1] * 100; -} - -static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year) -{ - unsigned char leap; - int ret; - - leap = (!(year % 4) && (year % 100)) || !(year % 400); - - if (rtctm->mon > 12 || rtctm->mon == 0 || rtctm->mday == 0) - return -EINVAL; - - if (rtctm->mday > (days_in_mon[rtctm->mon] + (rtctm->mon == 2 && leap))) - return -EINVAL; - - if (rtctm->hours >= 24 || rtctm->mins >= 60 || rtctm->secs >= 60) - return -EINVAL; - - /* - * The RTC's own 2-bit year must reflect the least - * significant two bits of the CMOS year. - */ - rtctm->year_off = (year % 100) & 3; - - ret = rtc_command(RTC_SETDATETIME, rtctm); - if (ret == 0) - ret = rtc_update_year(year); - - return ret; -} - -/* - * Set the RTC time only. Note that - * we do not touch the date. - */ -static int k_set_rtc_time(void) -{ - struct rtc_tm new_rtctm, old_rtctm; - unsigned long nowtime = xtime.tv_sec; - - if (rtc_command(RTC_GETDATETIME, &old_rtctm)) - return 0; - - new_rtctm.cs = xtime.tv_nsec / 10000000; - new_rtctm.secs = nowtime % 60; nowtime /= 60; - new_rtctm.mins = nowtime % 60; nowtime /= 60; - new_rtctm.hours = nowtime % 24; - - /* - * avoid writing when we're going to change the day - * of the month. We will retry in the next minute. - * This basically means that if the RTC must not drift - * by more than 1 minute in 11 minutes. - * - * [ rtc: 1/1/2000 23:58:00, real 2/1/2000 00:01:00, - * rtc gets set to 1/1/2000 00:01:00 ] - */ - if ((old_rtctm.hours == 23 && old_rtctm.mins == 59) || - (new_rtctm.hours == 23 && new_rtctm.mins == 59)) - return 1; - - return rtc_command(RTC_SETTIME, &new_rtctm); -} - -static int rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - unsigned int year; - struct rtc_time rtctm; - struct rtc_tm rtc_raw; - - switch (cmd) { - case RTC_ALM_READ: - case RTC_ALM_SET: - break; - - case RTC_RD_TIME: - memset(&rtctm, 0, sizeof(struct rtc_time)); - get_rtc_time(&rtc_raw, &year); - rtctm.tm_sec = rtc_raw.secs; - rtctm.tm_min = rtc_raw.mins; - rtctm.tm_hour = rtc_raw.hours; - rtctm.tm_mday = rtc_raw.mday; - rtctm.tm_mon = rtc_raw.mon - 1; /* month starts at 0 */ - rtctm.tm_year = year - 1900; /* starts at 1900 */ - return copy_to_user((void *)arg, &rtctm, sizeof(rtctm)) - ? -EFAULT : 0; - - case RTC_SET_TIME: - if (!capable(CAP_SYS_TIME)) - return -EACCES; - - if (copy_from_user(&rtctm, (void *)arg, sizeof(rtctm))) - return -EFAULT; - rtc_raw.secs = rtctm.tm_sec; - rtc_raw.mins = rtctm.tm_min; - rtc_raw.hours = rtctm.tm_hour; - rtc_raw.mday = rtctm.tm_mday; - rtc_raw.mon = rtctm.tm_mon + 1; - year = rtctm.tm_year + 1900; - return set_rtc_time(&rtc_raw, year); - break; - - case RTC_EPOCH_READ: - return put_user(1900, (unsigned long *)arg); - - } - return -EINVAL; -} - -static const struct file_operations rtc_fops = { - .ioctl = rtc_ioctl, -}; - -static struct miscdevice rtc_dev = { - .minor = RTC_MINOR, - .name = "rtc", - .fops = &rtc_fops, -}; - -/* IOC / IOMD i2c driver */ - -#define FORCE_ONES 0xdc -#define SCL 0x02 -#define SDA 0x01 - -/* - * We must preserve all non-i2c output bits in IOC_CONTROL. - * Note also that we need to preserve the value of SCL and - * SDA outputs as well (which may be different from the - * values read back from IOC_CONTROL). - */ -static u_int force_ones; - -static void ioc_setscl(void *data, int state) -{ - u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); - u_int ones = force_ones; - - if (state) - ones |= SCL; - else - ones &= ~SCL; - - force_ones = ones; - - ioc_writeb(ioc_control | ones, IOC_CONTROL); -} - -static void ioc_setsda(void *data, int state) -{ - u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); - u_int ones = force_ones; - - if (state) - ones |= SDA; - else - ones &= ~SDA; - - force_ones = ones; - - ioc_writeb(ioc_control | ones, IOC_CONTROL); -} - -static int ioc_getscl(void *data) -{ - return (ioc_readb(IOC_CONTROL) & SCL) != 0; -} - -static int ioc_getsda(void *data) -{ - return (ioc_readb(IOC_CONTROL) & SDA) != 0; -} - -static struct i2c_algo_bit_data ioc_data = { - .setsda = ioc_setsda, - .setscl = ioc_setscl, - .getsda = ioc_getsda, - .getscl = ioc_getscl, - .udelay = 80, - .timeout = 100 -}; - -static int ioc_client_reg(struct i2c_client *client) -{ - if (client->driver->id == I2C_DRIVERID_PCF8583 && - client->addr == 0x50) { - struct rtc_tm rtctm; - unsigned int year; - struct timespec tv; - - rtc_client = client; - get_rtc_time(&rtctm, &year); - - tv.tv_nsec = rtctm.cs * 10000000; - tv.tv_sec = mktime(year, rtctm.mon, rtctm.mday, - rtctm.hours, rtctm.mins, rtctm.secs); - do_settimeofday(&tv); - set_rtc = k_set_rtc_time; - } - - return 0; -} - -static int ioc_client_unreg(struct i2c_client *client) -{ - if (client == rtc_client) { - set_rtc = NULL; - rtc_client = NULL; - } - - return 0; -} - -static struct i2c_adapter ioc_ops = { - .id = I2C_HW_B_IOC, - .algo_data = &ioc_data, - .client_register = ioc_client_reg, - .client_unregister = ioc_client_unreg, -}; - -static int __init i2c_ioc_init(void) -{ - int ret; - - force_ones = FORCE_ONES | SCL | SDA; - - ret = i2c_bit_add_bus(&ioc_ops); - - if (ret >= 0){ - ret = misc_register(&rtc_dev); - if(ret < 0) - i2c_del_adapter(&ioc_ops); - } - - return ret; -} - -__initcall(i2c_ioc_init); diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c deleted file mode 100644 index 9b49f316ae9..00000000000 --- a/drivers/acorn/char/pcf8583.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * linux/drivers/acorn/char/pcf8583.c - * - * Copyright (C) 2000 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. - * - * Driver for PCF8583 RTC & RAM chip - */ -#include <linux/module.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/mc146818rtc.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/bcd.h> - -#include "pcf8583.h" - -static struct i2c_driver pcf8583_driver; - -static unsigned short ignore[] = { I2C_CLIENT_END }; -static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END }; -static unsigned short *forces[] = { NULL }; - -static struct i2c_client_address_data addr_data = { - .normal_i2c = normal_addr, - .probe = ignore, - .ignore = ignore, - .forces = forces, -}; - -#define set_ctrl(x, v) i2c_set_clientdata(x, (void *)(unsigned int)(v)) -#define get_ctrl(x) ((unsigned int)i2c_get_clientdata(x)) - -static int -pcf8583_attach(struct i2c_adapter *adap, int addr, int kind) -{ - struct i2c_client *c; - unsigned char buf[1], ad[1] = { 0 }; - struct i2c_msg msgs[2] = { - { - .addr = addr, - .flags = 0, - .len = 1, - .buf = ad, - }, { - .addr = addr, - .flags = I2C_M_RD, - .len = 1, - .buf = buf, - } - }; - - c = kmalloc(sizeof(*c), GFP_KERNEL); - if (!c) - return -ENOMEM; - - memset(c, 0, sizeof(*c)); - c->addr = addr; - c->adapter = adap; - c->driver = &pcf8583_driver; - - if (i2c_transfer(c->adapter, msgs, 2) == 2) - set_ctrl(c, buf[0]); - - return i2c_attach_client(c); -} - -static int -pcf8583_probe(struct i2c_adapter *adap) -{ - return i2c_probe(adap, &addr_data, pcf8583_attach); -} - -static int -pcf8583_detach(struct i2c_client *client) -{ - i2c_detach_client(client); - kfree(client); - return 0; -} - -static int -pcf8583_get_datetime(struct i2c_client *client, struct rtc_tm *dt) -{ - unsigned char buf[8], addr[1] = { 1 }; - struct i2c_msg msgs[2] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = addr, - }, { - .addr = client->addr, - .flags = I2C_M_RD, - .len = 6, - .buf = buf, - } - }; - int ret = -EIO; - - memset(buf, 0, sizeof(buf)); - - ret = i2c_transfer(client->adapter, msgs, 2); - if (ret == 2) { - dt->year_off = buf[4] >> 6; - dt->wday = buf[5] >> 5; - - buf[4] &= 0x3f; - buf[5] &= 0x1f; - - dt->cs = BCD_TO_BIN(buf[0]); - dt->secs = BCD_TO_BIN(buf[1]); - dt->mins = BCD_TO_BIN(buf[2]); - dt->hours = BCD_TO_BIN(buf[3]); - dt->mday = BCD_TO_BIN(buf[4]); - dt->mon = BCD_TO_BIN(buf[5]); - - ret = 0; - } - - return ret; -} - -static int -pcf8583_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo) -{ - unsigned char buf[8]; - int ret, len = 6; - - buf[0] = 0; - buf[1] = get_ctrl(client) | 0x80; - buf[2] = BIN_TO_BCD(dt->cs); - buf[3] = BIN_TO_BCD(dt->secs); - buf[4] = BIN_TO_BCD(dt->mins); - buf[5] = BIN_TO_BCD(dt->hours); - - if (datetoo) { - len = 8; - buf[6] = BIN_TO_BCD(dt->mday) | (dt->year_off << 6); - buf[7] = BIN_TO_BCD(dt->mon) | (dt->wday << 5); - } - - ret = i2c_master_send(client, (char *)buf, len); - if (ret == len) - ret = 0; - - buf[1] = get_ctrl(client); - i2c_master_send(client, (char *)buf, 2); - - return ret; -} - -static int -pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl) -{ - *ctrl = get_ctrl(client); - return 0; -} - -static int -pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl) -{ - unsigned char buf[2]; - - buf[0] = 0; - buf[1] = *ctrl; - set_ctrl(client, *ctrl); - - return i2c_master_send(client, (char *)buf, 2); -} - -static int -pcf8583_read_mem(struct i2c_client *client, struct mem *mem) -{ - unsigned char addr[1]; - struct i2c_msg msgs[2] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = addr, - }, { - .addr = client->addr, - .flags = I2C_M_RD, - .len = mem->nr, - .buf = mem->data, - } - }; - - if (mem->loc < 8) - return -EINVAL; - - addr[0] = mem->loc; - - return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; -} - -static int -pcf8583_write_mem(struct i2c_client *client, struct mem *mem) -{ - unsigned char addr[1]; - struct i2c_msg msgs[2] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = addr, - }, { - .addr = client->addr, - .flags = I2C_M_NOSTART, - .len = mem->nr, - .buf = mem->data, - } - }; - - if (mem->loc < 8) - return -EINVAL; - - addr[0] = mem->loc; - - return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; -} - -static int -pcf8583_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - switch (cmd) { - case RTC_GETDATETIME: - return pcf8583_get_datetime(client, arg); - - case RTC_SETTIME: - return pcf8583_set_datetime(client, arg, 0); - - case RTC_SETDATETIME: - return pcf8583_set_datetime(client, arg, 1); - - case RTC_GETCTRL: - return pcf8583_get_ctrl(client, arg); - - case RTC_SETCTRL: - return pcf8583_set_ctrl(client, arg); - - case MEM_READ: - return pcf8583_read_mem(client, arg); - - case MEM_WRITE: - return pcf8583_write_mem(client, arg); - - default: - return -EINVAL; - } -} - -static struct i2c_driver pcf8583_driver = { - .driver = { - .name = "PCF8583", - }, - .id = I2C_DRIVERID_PCF8583, - .attach_adapter = pcf8583_probe, - .detach_client = pcf8583_detach, - .command = pcf8583_command -}; - -static __init int pcf8583_init(void) -{ - return i2c_add_driver(&pcf8583_driver); -} - -static __exit void pcf8583_exit(void) -{ - i2c_del_driver(&pcf8583_driver); -} - -module_init(pcf8583_init); -module_exit(pcf8583_exit); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("PCF8583 I2C RTC driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/acorn/char/pcf8583.h b/drivers/acorn/char/pcf8583.h deleted file mode 100644 index 847f7fdb876..00000000000 --- a/drivers/acorn/char/pcf8583.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * linux/drivers/acorn/char/pcf8583.h - * - * Copyright (C) 2000 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. - */ -struct rtc_tm { - unsigned char cs; - unsigned char secs; - unsigned char mins; - unsigned char hours; - unsigned char mday; - unsigned char mon; - unsigned char year_off; - unsigned char wday; -}; - -struct mem { - unsigned int loc; - unsigned int nr; - unsigned char *data; -}; - -#define RTC_GETDATETIME 0 -#define RTC_SETTIME 1 -#define RTC_SETDATETIME 2 -#define RTC_GETCTRL 3 -#define RTC_SETCTRL 4 -#define MEM_READ 5 -#define MEM_WRITE 6 - -#define CTRL_STOP 0x80 -#define CTRL_HOLD 0x40 -#define CTRL_32KHZ 0x00 -#define CTRL_MASK 0x08 -#define CTRL_ALARMEN 0x04 -#define CTRL_ALARM 0x02 -#define CTRL_TIMER 0x01 diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index e942ffe8b57..7c49e103cf8 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -149,6 +149,7 @@ config ACPI_DOCK config ACPI_BAY tristate "Removable Drive Bay (EXPERIMENTAL)" depends on EXPERIMENTAL + depends on ACPI_DOCK help This driver adds support for ACPI controlled removable drive bays such as the IBM ultrabay or the Dell Module Bay. diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4af0a4bb578..d16b5b0c8b7 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -562,6 +562,15 @@ config PATA_IXP4XX_CF If unsure, say N. +config PATA_SCC + tristate "Toshiba's Cell Reference Set IDE support" + depends on PCI && PPC_IBM_CELL_BLADE + help + This option enables support for the built-in IDE controller on + Toshiba Cell Reference Board. + + If unsure, say N. + endif endmenu diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 74298afbbaa..13d7397e000 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_PATA_WINBOND_VLB) += pata_winbond.o obj-$(CONFIG_PATA_SIS) += pata_sis.o obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o +obj-$(CONFIG_PATA_SCC) += pata_scc.o obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o # Should be last but one libata driver obj-$(CONFIG_ATA_GENERIC) += ata_generic.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 6a3543e0624..dc7b5622592 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -46,7 +46,7 @@ #include <linux/libata.h> #define DRV_NAME "ahci" -#define DRV_VERSION "2.0" +#define DRV_VERSION "2.1" enum { @@ -198,9 +198,9 @@ struct ahci_port_priv { void *rx_fis; dma_addr_t rx_fis_dma; /* for NCQ spurious interrupt analysis */ - int ncq_saw_spurious_sdb_cnt; unsigned int ncq_saw_d2h:1; unsigned int ncq_saw_dmas:1; + unsigned int ncq_saw_sdb:1; }; static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg); @@ -219,10 +219,12 @@ static void ahci_thaw(struct ata_port *ap); static void ahci_error_handler(struct ata_port *ap); static void ahci_vt8251_error_handler(struct ata_port *ap); static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); +#ifdef CONFIG_PM static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg); static int ahci_port_resume(struct ata_port *ap); static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int ahci_pci_device_resume(struct pci_dev *pdev); +#endif static struct scsi_host_template ahci_sht = { .module = THIS_MODULE, @@ -241,8 +243,10 @@ static struct scsi_host_template ahci_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .suspend = ata_scsi_device_suspend, .resume = ata_scsi_device_resume, +#endif }; static const struct ata_port_operations ahci_ops = { @@ -271,8 +275,10 @@ static const struct ata_port_operations ahci_ops = { .error_handler = ahci_error_handler, .post_internal_cmd = ahci_post_internal_cmd, +#ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, +#endif .port_start = ahci_port_start, .port_stop = ahci_port_stop, @@ -304,8 +310,10 @@ static const struct ata_port_operations ahci_vt8251_ops = { .error_handler = ahci_vt8251_error_handler, .post_internal_cmd = ahci_post_internal_cmd, +#ifdef CONFIG_PM .port_suspend = ahci_port_suspend, .port_resume = ahci_port_resume, +#endif .port_start = ahci_port_start, .port_stop = ahci_port_stop, @@ -381,16 +389,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */ + { PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */ { PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */ { PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */ - /* JMicron */ - { PCI_VDEVICE(JMICRON, 0x2360), board_ahci_ign_iferr }, /* JMB360 */ - { PCI_VDEVICE(JMICRON, 0x2361), board_ahci_ign_iferr }, /* JMB361 */ - { PCI_VDEVICE(JMICRON, 0x2363), board_ahci_ign_iferr }, /* JMB363 */ - { PCI_VDEVICE(JMICRON, 0x2365), board_ahci_ign_iferr }, /* JMB365 */ - { PCI_VDEVICE(JMICRON, 0x2366), board_ahci_ign_iferr }, /* JMB366 */ + /* JMicron 360/1/3/5/6, match class to avoid IDE function */ + { PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr }, /* ATI */ { PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */ @@ -439,8 +445,10 @@ static struct pci_driver ahci_pci_driver = { .id_table = ahci_pci_tbl, .probe = ahci_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ahci_pci_device_suspend, .resume = ahci_pci_device_resume, +#endif }; @@ -580,6 +588,7 @@ static void ahci_power_up(void __iomem *port_mmio, u32 cap) writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD); } +#ifdef CONFIG_PM static void ahci_power_down(void __iomem *port_mmio, u32 cap) { u32 cmd, scontrol; @@ -597,6 +606,7 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap) cmd &= ~PORT_CMD_SPIN_UP; writel(cmd, port_mmio + PORT_CMD); } +#endif static void ahci_init_port(void __iomem *port_mmio, u32 cap, dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma) @@ -1160,23 +1170,32 @@ static void ahci_host_intr(struct ata_port *ap) known_irq = 1; } - if (status & PORT_IRQ_SDB_FIS && - pp->ncq_saw_spurious_sdb_cnt < 10) { - /* SDB FIS containing spurious completions might be - * dangerous, we need to know more about them. Print - * more of it. - */ + if (status & PORT_IRQ_SDB_FIS) { const __le32 *f = pp->rx_fis + RX_FIS_SDB; - ata_port_printk(ap, KERN_INFO, "Spurious SDB FIS during NCQ " - "issue=0x%x SAct=0x%x FIS=%08x:%08x%s\n", + if (le32_to_cpu(f[1])) { + /* SDB FIS containing spurious completions + * might be dangerous, whine and fail commands + * with HSM violation. EH will turn off NCQ + * after several such failures. + */ + ata_ehi_push_desc(ehi, + "spurious completions during NCQ " + "issue=0x%x SAct=0x%x FIS=%08x:%08x", readl(port_mmio + PORT_CMD_ISSUE), readl(port_mmio + PORT_SCR_ACT), - le32_to_cpu(f[0]), le32_to_cpu(f[1]), - pp->ncq_saw_spurious_sdb_cnt < 10 ? - "" : ", shutting up"); - - pp->ncq_saw_spurious_sdb_cnt++; + le32_to_cpu(f[0]), le32_to_cpu(f[1])); + ehi->err_mask |= AC_ERR_HSM; + ehi->action |= ATA_EH_SOFTRESET; + ata_port_freeze(ap); + } else { + if (!pp->ncq_saw_sdb) + ata_port_printk(ap, KERN_INFO, + "spurious SDB FIS %08x:%08x during NCQ, " + "this message won't be printed again\n", + le32_to_cpu(f[0]), le32_to_cpu(f[1])); + pp->ncq_saw_sdb = 1; + } known_irq = 1; } @@ -1329,6 +1348,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) } } +#ifdef CONFIG_PM static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg) { struct ahci_host_priv *hpriv = ap->host->private_data; @@ -1407,6 +1427,7 @@ static int ahci_pci_device_resume(struct pci_dev *pdev) return 0; } +#endif static int ahci_port_start(struct ata_port *ap) { @@ -1665,13 +1686,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); - if (pdev->vendor == PCI_VENDOR_ID_JMICRON) { - /* Function 1 is the PATA controller except on the 368, where - we are not AHCI anyway */ - if (PCI_FUNC(pdev->devfn)) - return -ENODEV; - } - rc = pcim_enable_device(pdev); if (rc) return rc; diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c index be66ea08da5..d8e79882b88 100644 --- a/drivers/ata/ata_generic.c +++ b/drivers/ata/ata_generic.c @@ -26,7 +26,7 @@ #include <linux/libata.h> #define DRV_NAME "ata_generic" -#define DRV_VERSION "0.2.10" +#define DRV_VERSION "0.2.11" /* * A generic parallel ATA driver using libata @@ -90,10 +90,10 @@ static int generic_set_mode(struct ata_port *ap, struct ata_device **unused) /* We do need the right mode information for DMA or PIO and this comes from the current configuration flags */ if (dma_enabled & (1 << (5 + i))) { - dev->xfer_mode = XFER_MW_DMA_0; - dev->xfer_shift = ATA_SHIFT_MWDMA; + ata_id_to_dma_mode(dev, XFER_MW_DMA_0); dev->flags &= ~ATA_DFLAG_PIO; } else { + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; dev->flags |= ATA_DFLAG_PIO; @@ -119,8 +119,10 @@ static struct scsi_host_template generic_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations generic_port_ops = { @@ -230,8 +232,10 @@ static struct pci_driver ata_generic_pci_driver = { .id_table = ata_generic, .probe = ata_generic_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init ata_generic_init(void) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 4d716c7347e..b952c584338 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -93,7 +93,7 @@ #include <linux/libata.h> #define DRV_NAME "ata_piix" -#define DRV_VERSION "2.00ac7" +#define DRV_VERSION "2.10ac1" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ @@ -169,8 +169,6 @@ static const struct pci_device_id piix_pci_tbl[] = { /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */ /* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */ { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, - { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, - { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 }, /* Intel PIIX4 */ { 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 }, /* Intel PIIX4 */ @@ -255,8 +253,10 @@ static struct pci_driver piix_pci_driver = { .id_table = piix_pci_tbl, .probe = piix_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static struct scsi_host_template piix_sht = { @@ -275,8 +275,10 @@ static struct scsi_host_template piix_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static const struct ata_port_operations piix_pata_ops = { @@ -665,14 +667,9 @@ static int ich_pata_prereset(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); - if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) { - ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n"); - ap->eh_context.i.action &= ~ATA_EH_RESET_MASK; - return 0; - } - + if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) + return -ENOENT; ich_pata_cbl_detect(ap); - return ata_std_prereset(ap); } diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index b4e8be5d292..019d8ffdde5 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -34,6 +34,13 @@ struct taskfile_array { u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ }; +/* + * Helper - belongs in the PCI layer somewhere eventually + */ +static int is_pci_dev(struct device *dev) +{ + return (dev->bus == &pci_bus_type); +} /** * sata_get_dev_handle - finds acpi_handle and PCI device.function @@ -53,6 +60,9 @@ static int sata_get_dev_handle(struct device *dev, acpi_handle *handle, struct pci_dev *pci_dev; acpi_integer addr; + if (!is_pci_dev(dev)) + return -ENODEV; + pci_dev = to_pci_dev(dev); /* NOTE: PCI-specific */ /* Please refer to the ACPI spec for the syntax of _ADR. */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); @@ -84,7 +94,12 @@ static int pata_get_dev_handle(struct device *dev, acpi_handle *handle, acpi_status status; struct acpi_device_info *dinfo = NULL; int ret = -ENODEV; - struct pci_dev *pdev = to_pci_dev(dev); + struct pci_dev *pdev; + + if (!is_pci_dev(dev)) + return -ENODEV; + + pdev = to_pci_dev(dev); bus = pdev->bus->number; devnum = PCI_SLOT(pdev->devfn); @@ -294,9 +309,8 @@ static int do_drive_get_GTF(struct ata_port *ap, int ix, return 0; if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: ENTER: ap->id: %d, port#: %d\n", - __FUNCTION__, ap->id, ap->port_no); + ata_dev_printk(atadev, KERN_DEBUG, "%s: ENTER: port#: %d\n", + __FUNCTION__, ap->port_no); if (!ata_dev_enabled(atadev) || (ap->flags & ATA_FLAG_DISABLED)) { if (ata_msg_probe(ap)) @@ -456,6 +470,9 @@ static void taskfile_load_raw(struct ata_port *ap, struct ata_device *atadev, const struct taskfile_array *gtf) { + struct ata_taskfile tf; + unsigned int err; + if (ata_msg_probe(ap)) ata_dev_printk(atadev, KERN_DEBUG, "%s: (0x1f1-1f7): hex: " "%02x %02x %02x %02x %02x %02x %02x\n", @@ -468,35 +485,25 @@ static void taskfile_load_raw(struct ata_port *ap, && (gtf->tfa[6] == 0)) return; - if (ap->ops->qc_issue) { - struct ata_taskfile tf; - unsigned int err; - - ata_tf_init(atadev, &tf); - - /* convert gtf to tf */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ - tf.protocol = atadev->class == ATA_DEV_ATAPI ? - ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA; - tf.feature = gtf->tfa[0]; /* 0x1f1 */ - tf.nsect = gtf->tfa[1]; /* 0x1f2 */ - tf.lbal = gtf->tfa[2]; /* 0x1f3 */ - tf.lbam = gtf->tfa[3]; /* 0x1f4 */ - tf.lbah = gtf->tfa[4]; /* 0x1f5 */ - tf.device = gtf->tfa[5]; /* 0x1f6 */ - tf.command = gtf->tfa[6]; /* 0x1f7 */ - - err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0); - if (err && ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_ERR, - "%s: ata_exec_internal failed: %u\n", - __FUNCTION__, err); - } else - if (ata_msg_warn(ap)) - ata_dev_printk(atadev, KERN_WARNING, - "%s: SATA driver is missing qc_issue function" - " entry points\n", - __FUNCTION__); + ata_tf_init(atadev, &tf); + + /* convert gtf to tf */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ + tf.protocol = atadev->class == ATA_DEV_ATAPI ? + ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA; + tf.feature = gtf->tfa[0]; /* 0x1f1 */ + tf.nsect = gtf->tfa[1]; /* 0x1f2 */ + tf.lbal = gtf->tfa[2]; /* 0x1f3 */ + tf.lbam = gtf->tfa[3]; /* 0x1f4 */ + tf.lbah = gtf->tfa[4]; /* 0x1f5 */ + tf.device = gtf->tfa[5]; /* 0x1f6 */ + tf.command = gtf->tfa[6]; /* 0x1f7 */ + + err = ata_exec_internal(atadev, &tf, NULL, DMA_NONE, NULL, 0); + if (err && ata_msg_probe(ap)) + ata_dev_printk(atadev, KERN_ERR, + "%s: ata_exec_internal failed: %u\n", + __FUNCTION__, err); } /** @@ -521,9 +528,8 @@ static int do_drive_set_taskfiles(struct ata_port *ap, struct taskfile_array *gtf; if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: ENTER: ap->id: %d, port#: %d\n", - __FUNCTION__, ap->id, ap->port_no); + ata_dev_printk(atadev, KERN_DEBUG, "%s: ENTER: port#: %d\n", + __FUNCTION__, ap->port_no); if (noacpi || !(ap->cbl == ATA_CBL_SATA)) return 0; @@ -627,9 +633,8 @@ int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) return 0; if (ata_msg_probe(ap)) - ata_dev_printk(atadev, KERN_DEBUG, - "%s: ap->id: %d, ix = %d, port#: %d\n", - __FUNCTION__, ap->id, ix, ap->port_no); + ata_dev_printk(atadev, KERN_DEBUG, "%s: ix = %d, port#: %d\n", + __FUNCTION__, ix, ap->port_no); /* Don't continue if not a SATA device. */ if (!(ap->cbl == ATA_CBL_SATA)) { @@ -685,9 +690,8 @@ int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) if (err < 0) { if (ata_msg_probe(ap)) ata_dev_printk(atadev, KERN_DEBUG, - "ata%u(%u): %s _SDD error: status = 0x%x\n", - ap->id, ap->device->devno, - __FUNCTION__, status); + "%s _SDD error: status = 0x%x\n", + __FUNCTION__, status); } /* always return success */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index e900c5edefc..3c1f8830ac8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -59,7 +59,7 @@ #include "libata.h" -#define DRV_VERSION "2.10" /* must be exactly four chars */ +#define DRV_VERSION "2.20" /* must be exactly four chars */ /* debounce timing parameters in msecs { interval, duration, timeout } */ @@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev, static unsigned int ata_dev_set_xfermode(struct ata_device *dev); static void ata_dev_xfermask(struct ata_device *dev); -static unsigned int ata_unique_id = 1; +static unsigned int ata_print_id = 1; static struct workqueue_struct *ata_wq; struct workqueue_struct *ata_aux_wq; @@ -315,9 +315,7 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev, tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->flags |= tf_flags; - if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF | - ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ && - likely(tag != ATA_TAG_INTERNAL)) { + if (ata_ncq_enabled(dev) && likely(tag != ATA_TAG_INTERNAL)) { /* yay, NCQ */ if (!lba_48_ok(block, n_block)) return -ERANGE; @@ -600,6 +598,8 @@ void ata_dev_disable(struct ata_device *dev) { if (ata_dev_enabled(dev) && ata_msg_drv(dev->ap)) { ata_dev_printk(dev, KERN_WARNING, "disabled\n"); + ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | + ATA_DNXFER_QUIET); dev->class++; } } @@ -708,7 +708,7 @@ unsigned int ata_dev_classify(const struct ata_taskfile *tf) * Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE. */ -static unsigned int +unsigned int ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err) { struct ata_taskfile tf; @@ -824,6 +824,48 @@ static u64 ata_id_n_sectors(const u16 *id) } /** + * ata_id_to_dma_mode - Identify DMA mode from id block + * @dev: device to identify + * @mode: mode to assume if we cannot tell + * + * Set up the timing values for the device based upon the identify + * reported values for the DMA mode. This function is used by drivers + * which rely upon firmware configured modes, but wish to report the + * mode correctly when possible. + * + * In addition we emit similarly formatted messages to the default + * ata_dev_set_mode handler, in order to provide consistency of + * presentation. + */ + +void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown) +{ + unsigned int mask; + u8 mode; + + /* Pack the DMA modes */ + mask = ((dev->id[63] >> 8) << ATA_SHIFT_MWDMA) & ATA_MASK_MWDMA; + if (dev->id[53] & 0x04) + mask |= ((dev->id[88] >> 8) << ATA_SHIFT_UDMA) & ATA_MASK_UDMA; + + /* Select the mode in use */ + mode = ata_xfer_mask2mode(mask); + + if (mode != 0) { + ata_dev_printk(dev, KERN_INFO, "configured for %s\n", + ata_mode_string(mask)); + } else { + /* SWDMA perhaps ? */ + mode = unknown; + ata_dev_printk(dev, KERN_INFO, "configured for DMA\n"); + } + + /* Configure the device reporting */ + dev->xfer_mode = mode; + dev->xfer_shift = ata_xfer_mode2shift(mode); +} + +/** * ata_noop_dev_select - Select device 0/1 on ATA bus * @ap: ATA channel to manipulate * @device: ATA device (numbered from zero) to select @@ -891,8 +933,8 @@ void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep) { if (ata_msg_probe(ap)) - ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: " - "device %u, wait %u\n", ap->id, device, wait); + ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, " + "device %u, wait %u\n", device, wait); if (wait) ata_wait_idle(ap); @@ -1392,8 +1434,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, int rc; if (ata_msg_ctl(ap)) - ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", - __FUNCTION__, ap->id, dev->devno); + ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__); ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */ @@ -1430,7 +1471,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, if (err_mask) { if (err_mask & AC_ERR_NODEV_HINT) { DPRINTK("ata%u.%d: NODEV after polling detection\n", - ap->id, dev->devno); + ap->print_id, dev->devno); return -ENOENT; } @@ -1558,15 +1599,13 @@ int ata_dev_configure(struct ata_device *dev) int rc; if (!ata_dev_enabled(dev) && ata_msg_info(ap)) { - ata_dev_printk(dev, KERN_INFO, - "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n", - __FUNCTION__, ap->id, dev->devno); + ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT -- nodev\n", + __FUNCTION__); return 0; } if (ata_msg_probe(ap)) - ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n", - __FUNCTION__, ap->id, dev->devno); + ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__); /* set _SDD */ rc = ata_acpi_push_id(ap, dev->devno); @@ -1610,8 +1649,9 @@ int ata_dev_configure(struct ata_device *dev) if (dev->class == ATA_DEV_ATA) { if (ata_id_is_cfa(id)) { if (id[162] & 1) /* CPRM may make this media unusable */ - ata_dev_printk(dev, KERN_WARNING, "ata%u: device %u supports DRM functions and may not be fully accessable.\n", - ap->id, dev->devno); + ata_dev_printk(dev, KERN_WARNING, + "supports DRM functions and may " + "not be fully accessable.\n"); snprintf(revbuf, 7, "CFA"); } else @@ -1679,7 +1719,7 @@ int ata_dev_configure(struct ata_device *dev) "%s: %s, %s, max %s\n", revbuf, modelbuf, fwrevbuf, ata_mode_string(xfer_mask)); - ata_dev_printk(dev, KERN_INFO, + ata_dev_printk(dev, KERN_INFO, "%Lu sectors, multi %u, CHS %u/%u/%u\n", (unsigned long long)dev->n_sectors, dev->multi_count, dev->cylinders, @@ -1778,7 +1818,7 @@ int ata_bus_probe(struct ata_port *ap) { unsigned int classes[ATA_MAX_DEVICES]; int tries[ATA_MAX_DEVICES]; - int i, rc, down_xfermask; + int i, rc; struct ata_device *dev; ata_port_probe(ap); @@ -1787,8 +1827,6 @@ int ata_bus_probe(struct ata_port *ap) tries[i] = ATA_PROBE_MAX_TRIES; retry: - down_xfermask = 0; - /* reset and determine device classes */ ap->ops->phy_reset(ap); @@ -1812,8 +1850,11 @@ int ata_bus_probe(struct ata_port *ap) for (i = 0; i < ATA_MAX_DEVICES; i++) ap->device[i].pio_mode = XFER_PIO_0; - /* read IDENTIFY page and configure devices */ - for (i = 0; i < ATA_MAX_DEVICES; i++) { + /* read IDENTIFY page and configure devices. We have to do the identify + specific sequence bass-ackwards so that PDIAG- is released by + the slave device */ + + for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) { dev = &ap->device[i]; if (tries[i]) @@ -1826,6 +1867,15 @@ int ata_bus_probe(struct ata_port *ap) dev->id); if (rc) goto fail; + } + + /* After the identify sequence we can now set up the devices. We do + this in the normal order so that the user doesn't get confused */ + + for(i = 0; i < ATA_MAX_DEVICES; i++) { + dev = &ap->device[i]; + if (!ata_dev_enabled(dev)) + continue; ap->eh_context.i.flags |= ATA_EHI_PRINTINFO; rc = ata_dev_configure(dev); @@ -1836,10 +1886,8 @@ int ata_bus_probe(struct ata_port *ap) /* configure transfer mode */ rc = ata_set_mode(ap, &dev); - if (rc) { - down_xfermask = 1; + if (rc) goto fail; - } for (i = 0; i < ATA_MAX_DEVICES; i++) if (ata_dev_enabled(&ap->device[i])) @@ -1851,25 +1899,29 @@ int ata_bus_probe(struct ata_port *ap) return -ENODEV; fail: + tries[dev->devno]--; + switch (rc) { case -EINVAL: - case -ENODEV: + /* eeek, something went very wrong, give up */ tries[dev->devno] = 0; break; + + case -ENODEV: + /* give it just one more chance */ + tries[dev->devno] = min(tries[dev->devno], 1); case -EIO: - sata_down_spd_limit(ap); - /* fall through */ - default: - tries[dev->devno]--; - if (down_xfermask && - ata_down_xfermask_limit(dev, tries[dev->devno] == 1)) - tries[dev->devno] = 0; + if (tries[dev->devno] == 1) { + /* This is the last chance, better to slow + * down than lose it. + */ + sata_down_spd_limit(ap); + ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); + } } - if (!tries[dev->devno]) { - ata_down_xfermask_limit(dev, 1); + if (!tries[dev->devno]) ata_dev_disable(dev); - } goto retry; } @@ -2300,7 +2352,7 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, /** * ata_down_xfermask_limit - adjust dev xfer masks downward * @dev: Device to adjust xfer masks - * @force_pio0: Force PIO0 + * @sel: ATA_DNXFER_* selector * * Adjust xfer masks of @dev downward. Note that this function * does not apply the change. Invoking ata_set_mode() afterwards @@ -2312,37 +2364,78 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed, * RETURNS: * 0 on success, negative errno on failure */ -int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0) +int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel) { - unsigned long xfer_mask; - int highbit; + char buf[32]; + unsigned int orig_mask, xfer_mask; + unsigned int pio_mask, mwdma_mask, udma_mask; + int quiet, highbit; - xfer_mask = ata_pack_xfermask(dev->pio_mask, dev->mwdma_mask, - dev->udma_mask); + quiet = !!(sel & ATA_DNXFER_QUIET); + sel &= ~ATA_DNXFER_QUIET; - if (!xfer_mask) - goto fail; - /* don't gear down to MWDMA from UDMA, go directly to PIO */ - if (xfer_mask & ATA_MASK_UDMA) - xfer_mask &= ~ATA_MASK_MWDMA; + xfer_mask = orig_mask = ata_pack_xfermask(dev->pio_mask, + dev->mwdma_mask, + dev->udma_mask); + ata_unpack_xfermask(xfer_mask, &pio_mask, &mwdma_mask, &udma_mask); - highbit = fls(xfer_mask) - 1; - xfer_mask &= ~(1 << highbit); - if (force_pio0) - xfer_mask &= 1 << ATA_SHIFT_PIO; - if (!xfer_mask) - goto fail; + switch (sel) { + case ATA_DNXFER_PIO: + highbit = fls(pio_mask) - 1; + pio_mask &= ~(1 << highbit); + break; + + case ATA_DNXFER_DMA: + if (udma_mask) { + highbit = fls(udma_mask) - 1; + udma_mask &= ~(1 << highbit); + if (!udma_mask) + return -ENOENT; + } else if (mwdma_mask) { + highbit = fls(mwdma_mask) - 1; + mwdma_mask &= ~(1 << highbit); + if (!mwdma_mask) + return -ENOENT; + } + break; + + case ATA_DNXFER_40C: + udma_mask &= ATA_UDMA_MASK_40C; + break; + + case ATA_DNXFER_FORCE_PIO0: + pio_mask &= 1; + case ATA_DNXFER_FORCE_PIO: + mwdma_mask = 0; + udma_mask = 0; + break; + + default: + BUG(); + } + + xfer_mask &= ata_pack_xfermask(pio_mask, mwdma_mask, udma_mask); + + if (!(xfer_mask & ATA_MASK_PIO) || xfer_mask == orig_mask) + return -ENOENT; + + if (!quiet) { + if (xfer_mask & (ATA_MASK_MWDMA | ATA_MASK_UDMA)) + snprintf(buf, sizeof(buf), "%s:%s", + ata_mode_string(xfer_mask), + ata_mode_string(xfer_mask & ATA_MASK_PIO)); + else + snprintf(buf, sizeof(buf), "%s", + ata_mode_string(xfer_mask)); + + ata_dev_printk(dev, KERN_WARNING, + "limiting speed to %s\n", buf); + } ata_unpack_xfermask(xfer_mask, &dev->pio_mask, &dev->mwdma_mask, &dev->udma_mask); - ata_dev_printk(dev, KERN_WARNING, "limiting speed to %s\n", - ata_mode_string(xfer_mask)); - return 0; - - fail: - return -EINVAL; } static int ata_dev_set_mode(struct ata_device *dev) @@ -2475,12 +2568,11 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev) * host channels are not permitted to do so. */ if (used_dma && (ap->host->flags & ATA_HOST_SIMPLEX)) - ap->host->simplex_claimed = 1; + ap->host->simplex_claimed = ap; /* step5: chip specific finalisation */ if (ap->ops->post_set_mode) ap->ops->post_set_mode(ap); - out: if (rc) *r_failed_dev = dev; @@ -2609,7 +2701,7 @@ static unsigned int ata_bus_softreset(struct ata_port *ap, { struct ata_ioports *ioaddr = &ap->ioaddr; - DPRINTK("ata%u: bus reset via SRST\n", ap->id); + DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); /* software reset. causes dev0 to be selected */ iowrite8(ap->ctl, ioaddr->ctl_addr); @@ -2669,7 +2761,7 @@ void ata_bus_reset(struct ata_port *ap) u8 err; unsigned int dev0, dev1 = 0, devmask = 0; - DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no); + DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no); /* determine if device 0/1 are present */ if (ap->flags & ATA_FLAG_SATA_RESET) @@ -3256,7 +3348,6 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "WPI CDD-820", NULL, ATA_HORKAGE_NODMA }, { "SAMSUNG CD-ROM SC-148C", NULL, ATA_HORKAGE_NODMA }, { "SAMSUNG CD-ROM SC", NULL, ATA_HORKAGE_NODMA }, - { "SanDisk SDP3B-64", NULL, ATA_HORKAGE_NODMA }, { "ATAPI CD-ROM DRIVE 40X MAXIMUM",NULL,ATA_HORKAGE_NODMA }, { "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA }, { "SAMSUNG CD-ROM SN-124","N001", ATA_HORKAGE_NODMA }, @@ -3266,6 +3357,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Devices where NCQ should be avoided */ /* NCQ is slow */ { "WDC WD740ADFD-00", NULL, ATA_HORKAGE_NONCQ }, + /* http://thread.gmane.org/gmane.linux.ide/14907 */ + { "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ }, /* Devices with NCQ limits */ @@ -3362,7 +3455,8 @@ static void ata_dev_xfermask(struct ata_device *dev) "device is on DMA blacklist, disabling DMA\n"); } - if ((host->flags & ATA_HOST_SIMPLEX) && host->simplex_claimed) { + if ((host->flags & ATA_HOST_SIMPLEX) && + host->simplex_claimed && host->simplex_claimed != ap) { xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); ata_dev_printk(dev, KERN_WARNING, "simplex DMA is claimed by " "other device, disabling DMA\n"); @@ -3739,7 +3833,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) struct scatterlist *lsg = &sg[qc->n_elem - 1]; int n_elem, pre_n_elem, dir, trim_sg = 0; - VPRINTK("ENTER, ata%u\n", ap->id); + VPRINTK("ENTER, ata%u\n", ap->print_id); WARN_ON(!(qc->flags & ATA_QCFLAG_SG)); /* we must lengthen transfers to end on a 32-bit boundary */ @@ -4140,7 +4234,7 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) if (do_write != i_write) goto err_out; - VPRINTK("ata%u: xfering %d bytes\n", ap->id, bytes); + VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes); __atapi_pio_bytes(qc, bytes); @@ -4257,7 +4351,7 @@ int ata_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, fsm_start: DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", - ap->id, qc->tf.protocol, ap->hsm_task_state, status); + ap->print_id, qc->tf.protocol, ap->hsm_task_state, status); switch (ap->hsm_task_state) { case HSM_ST_FIRST: @@ -4290,8 +4384,8 @@ fsm_start: * let the EH abort the command or reset the device. */ if (unlikely(status & (ATA_ERR | ATA_DF))) { - printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n", - ap->id, status); + ata_port_printk(ap, KERN_WARNING, "DRQ=1 with device " + "error, dev_stat 0x%X\n", status); qc->err_mask |= AC_ERR_HSM; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; @@ -4348,8 +4442,9 @@ fsm_start: * let the EH abort the command or reset the device. */ if (unlikely(status & (ATA_ERR | ATA_DF))) { - printk(KERN_WARNING "ata%d: DRQ=1 with device error, dev_stat 0x%X\n", - ap->id, status); + ata_port_printk(ap, KERN_WARNING, "DRQ=1 with " + "device error, dev_stat 0x%X\n", + status); qc->err_mask |= AC_ERR_HSM; ap->hsm_task_state = HSM_ST_ERR; goto fsm_start; @@ -4435,7 +4530,7 @@ fsm_start: /* no more data to transfer */ DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n", - ap->id, qc->dev->devno, status); + ap->print_id, qc->dev->devno, status); WARN_ON(qc->err_mask); @@ -4977,7 +5072,7 @@ inline unsigned int ata_host_intr (struct ata_port *ap, u8 status, host_stat = 0; VPRINTK("ata%u: protocol %d task_state %d\n", - ap->id, qc->tf.protocol, ap->hsm_task_state); + ap->print_id, qc->tf.protocol, ap->hsm_task_state); /* Check whether we are expecting interrupt in this state */ switch (ap->hsm_task_state) { @@ -4998,7 +5093,8 @@ inline unsigned int ata_host_intr (struct ata_port *ap, qc->tf.protocol == ATA_PROT_ATAPI_DMA) { /* check status of DMA engine */ host_stat = ap->ops->bmdma_status(ap); - VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat); + VPRINTK("ata%u: host_stat 0x%X\n", + ap->print_id, host_stat); /* if it's not our irq... */ if (!(host_stat & ATA_DMA_INTR)) @@ -5259,6 +5355,7 @@ int ata_flush_cache(struct ata_device *dev) return 0; } +#ifdef CONFIG_PM static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg, unsigned int action, unsigned int ehi_flags, int wait) @@ -5374,6 +5471,7 @@ void ata_host_resume(struct ata_host *host) ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0); host->dev->power.power_state = PMSG_ON; } +#endif /** * ata_port_start - Set port up for dma. @@ -5457,7 +5555,7 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host, ap->lock = &host->lock; ap->flags = ATA_FLAG_DISABLED; - ap->id = ata_unique_id++; + ap->print_id = ata_print_id++; ap->ctl = ATA_DEVCTL_OBS; ap->host = host; ap->dev = ent->dev; @@ -5528,7 +5626,7 @@ static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost) { ap->scsi_host = shost; - shost->unique_id = ap->id; + shost->unique_id = ap->print_id; shost->max_id = 16; shost->max_lun = 1; shost->max_channel = 1; @@ -5587,17 +5685,23 @@ static void ata_host_release(struct device *gendev, void *res) for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - if (!ap) - continue; - - if (ap->ops->port_stop) + if (ap && ap->ops->port_stop) ap->ops->port_stop(ap); - - scsi_host_put(ap->scsi_host); } if (host->ops->host_stop) host->ops->host_stop(host); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap = host->ports[i]; + + if (ap) + scsi_host_put(ap->scsi_host); + + host->ports[i] = NULL; + } + + dev_set_drvdata(gendev, NULL); } /** @@ -5792,9 +5896,9 @@ int ata_device_add(const struct ata_probe_ent *ent) /* wait for EH to finish */ ata_port_wait_eh(ap); } else { - DPRINTK("ata%u: bus probe begin\n", ap->id); + DPRINTK("ata%u: bus probe begin\n", ap->print_id); rc = ata_bus_probe(ap); - DPRINTK("ata%u: bus probe end\n", ap->id); + DPRINTK("ata%u: bus probe end\n", ap->print_id); if (rc) { /* FIXME: do something useful here? @@ -5820,7 +5924,6 @@ int ata_device_add(const struct ata_probe_ent *ent) err_out: devres_release_group(dev, ata_device_add); - dev_set_drvdata(dev, NULL); VPRINTK("EXIT, returning %d\n", rc); return 0; } @@ -5905,11 +6008,7 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) { struct ata_probe_ent *probe_ent; - /* XXX - the following if can go away once all LLDs are managed */ - if (!list_empty(&dev->devres_head)) - probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); - else - probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", kobject_name(&(dev->kobj))); @@ -6012,14 +6111,14 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits) return (tmp == bits->val) ? 1 : 0; } +#ifdef CONFIG_PM void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg) { pci_save_state(pdev); + pci_disable_device(pdev); - if (mesg.event == PM_EVENT_SUSPEND) { - pci_disable_device(pdev); + if (mesg.event == PM_EVENT_SUSPEND) pci_set_power_state(pdev, PCI_D3hot); - } } int ata_pci_device_do_resume(struct pci_dev *pdev) @@ -6064,6 +6163,8 @@ int ata_pci_device_resume(struct pci_dev *pdev) ata_host_resume(host); return rc; } +#endif /* CONFIG_PM */ + #endif /* CONFIG_PCI */ @@ -6241,6 +6342,7 @@ EXPORT_SYMBOL_GPL(ata_bmdma_drive_eh); EXPORT_SYMBOL_GPL(ata_bmdma_error_handler); EXPORT_SYMBOL_GPL(ata_bmdma_post_internal_cmd); EXPORT_SYMBOL_GPL(ata_port_probe); +EXPORT_SYMBOL_GPL(ata_dev_disable); EXPORT_SYMBOL_GPL(sata_set_spd); EXPORT_SYMBOL_GPL(sata_phy_debounce); EXPORT_SYMBOL_GPL(sata_phy_resume); @@ -6271,10 +6373,13 @@ EXPORT_SYMBOL_GPL(sata_scr_write); EXPORT_SYMBOL_GPL(sata_scr_write_flush); EXPORT_SYMBOL_GPL(ata_port_online); EXPORT_SYMBOL_GPL(ata_port_offline); +#ifdef CONFIG_PM EXPORT_SYMBOL_GPL(ata_host_suspend); EXPORT_SYMBOL_GPL(ata_host_resume); +#endif /* CONFIG_PM */ EXPORT_SYMBOL_GPL(ata_id_string); EXPORT_SYMBOL_GPL(ata_id_c_string); +EXPORT_SYMBOL_GPL(ata_id_to_dma_mode); EXPORT_SYMBOL_GPL(ata_device_blacklisted); EXPORT_SYMBOL_GPL(ata_scsi_simulate); @@ -6287,16 +6392,20 @@ EXPORT_SYMBOL_GPL(pci_test_config_bits); EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); +#ifdef CONFIG_PM EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend); EXPORT_SYMBOL_GPL(ata_pci_device_do_resume); EXPORT_SYMBOL_GPL(ata_pci_device_suspend); EXPORT_SYMBOL_GPL(ata_pci_device_resume); +#endif /* CONFIG_PM */ EXPORT_SYMBOL_GPL(ata_pci_default_filter); EXPORT_SYMBOL_GPL(ata_pci_clear_simplex); #endif /* CONFIG_PCI */ +#ifdef CONFIG_PM EXPORT_SYMBOL_GPL(ata_scsi_device_suspend); EXPORT_SYMBOL_GPL(ata_scsi_device_resume); +#endif /* CONFIG_PM */ EXPORT_SYMBOL_GPL(ata_eng_timeout); EXPORT_SYMBOL_GPL(ata_port_schedule_eh); @@ -6311,3 +6420,4 @@ EXPORT_SYMBOL_GPL(ata_irq_on); EXPORT_SYMBOL_GPL(ata_dummy_irq_on); EXPORT_SYMBOL_GPL(ata_irq_ack); EXPORT_SYMBOL_GPL(ata_dummy_irq_ack); +EXPORT_SYMBOL_GPL(ata_dev_try_classify); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 52c85af7fe9..7349c3dbf77 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -44,10 +44,41 @@ #include "libata.h" +enum { + ATA_EH_SPDN_NCQ_OFF = (1 << 0), + ATA_EH_SPDN_SPEED_DOWN = (1 << 1), + ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2), +}; + static void __ata_port_freeze(struct ata_port *ap); static void ata_eh_finish(struct ata_port *ap); +#ifdef CONFIG_PM static void ata_eh_handle_port_suspend(struct ata_port *ap); static void ata_eh_handle_port_resume(struct ata_port *ap); +static int ata_eh_suspend(struct ata_port *ap, + struct ata_device **r_failed_dev); +static void ata_eh_prep_resume(struct ata_port *ap); +static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev); +#else /* CONFIG_PM */ +static void ata_eh_handle_port_suspend(struct ata_port *ap) +{ } + +static void ata_eh_handle_port_resume(struct ata_port *ap) +{ } + +static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev) +{ + return 0; +} + +static void ata_eh_prep_resume(struct ata_port *ap) +{ } + +static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev) +{ + return 0; +} +#endif /* CONFIG_PM */ static void ata_ering_record(struct ata_ering *ering, int is_io, unsigned int err_mask) @@ -65,12 +96,9 @@ static void ata_ering_record(struct ata_ering *ering, int is_io, ent->timestamp = get_jiffies_64(); } -static struct ata_ering_entry * ata_ering_top(struct ata_ering *ering) +static void ata_ering_clear(struct ata_ering *ering) { - struct ata_ering_entry *ent = &ering->ring[ering->cursor]; - if (!ent->err_mask) - return NULL; - return ent; + memset(ering, 0, sizeof(*ering)); } static int ata_ering_map(struct ata_ering *ering, @@ -585,7 +613,7 @@ static void __ata_port_freeze(struct ata_port *ap) ap->pflags |= ATA_PFLAG_FROZEN; - DPRINTK("ata%u port frozen\n", ap->id); + DPRINTK("ata%u port frozen\n", ap->print_id); } /** @@ -658,7 +686,7 @@ void ata_eh_thaw_port(struct ata_port *ap) spin_unlock_irqrestore(ap->lock, flags); - DPRINTK("ata%u port thawed\n", ap->id); + DPRINTK("ata%u port thawed\n", ap->print_id); } static void ata_eh_scsidone(struct scsi_cmnd *scmd) @@ -1159,87 +1187,99 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc, return action; } -static int ata_eh_categorize_ering_entry(struct ata_ering_entry *ent) +static int ata_eh_categorize_error(int is_io, unsigned int err_mask) { - if (ent->err_mask & (AC_ERR_ATA_BUS | AC_ERR_TIMEOUT)) + if (err_mask & AC_ERR_ATA_BUS) return 1; - if (ent->is_io) { - if (ent->err_mask & AC_ERR_HSM) - return 1; - if ((ent->err_mask & - (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV) + if (err_mask & AC_ERR_TIMEOUT) + return 2; + + if (is_io) { + if (err_mask & AC_ERR_HSM) return 2; + if ((err_mask & + (AC_ERR_DEV|AC_ERR_MEDIA|AC_ERR_INVALID)) == AC_ERR_DEV) + return 3; } return 0; } -struct speed_down_needed_arg { +struct speed_down_verdict_arg { u64 since; - int nr_errors[3]; + int nr_errors[4]; }; -static int speed_down_needed_cb(struct ata_ering_entry *ent, void *void_arg) +static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg) { - struct speed_down_needed_arg *arg = void_arg; + struct speed_down_verdict_arg *arg = void_arg; + int cat = ata_eh_categorize_error(ent->is_io, ent->err_mask); if (ent->timestamp < arg->since) return -1; - arg->nr_errors[ata_eh_categorize_ering_entry(ent)]++; + arg->nr_errors[cat]++; return 0; } /** - * ata_eh_speed_down_needed - Determine wheter speed down is necessary + * ata_eh_speed_down_verdict - Determine speed down verdict * @dev: Device of interest * * This function examines error ring of @dev and determines - * whether speed down is necessary. Speed down is necessary if - * there have been more than 3 of Cat-1 errors or 10 of Cat-2 - * errors during last 15 minutes. + * whether NCQ needs to be turned off, transfer speed should be + * stepped down, or falling back to PIO is necessary. * - * Cat-1 errors are ATA_BUS, TIMEOUT for any command and HSM - * violation for known supported commands. + * Cat-1 is ATA_BUS error for any command. * - * Cat-2 errors are unclassified DEV error for known supported + * Cat-2 is TIMEOUT for any command or HSM violation for known + * supported commands. + * + * Cat-3 is is unclassified DEV error for known supported * command. * + * NCQ needs to be turned off if there have been more than 3 + * Cat-2 + Cat-3 errors during last 10 minutes. + * + * Speed down is necessary if there have been more than 3 Cat-1 + + * Cat-2 errors or 10 Cat-3 errors during last 10 minutes. + * + * Falling back to PIO mode is necessary if there have been more + * than 10 Cat-1 + Cat-2 + Cat-3 errors during last 5 minutes. + * * LOCKING: * Inherited from caller. * * RETURNS: - * 1 if speed down is necessary, 0 otherwise + * OR of ATA_EH_SPDN_* flags. */ -static int ata_eh_speed_down_needed(struct ata_device *dev) +static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev) { - const u64 interval = 15LLU * 60 * HZ; - static const int err_limits[3] = { -1, 3, 10 }; - struct speed_down_needed_arg arg; - struct ata_ering_entry *ent; - int err_cat; - u64 j64; + const u64 j5mins = 5LLU * 60 * HZ, j10mins = 10LLU * 60 * HZ; + u64 j64 = get_jiffies_64(); + struct speed_down_verdict_arg arg; + unsigned int verdict = 0; - ent = ata_ering_top(&dev->ering); - if (!ent) - return 0; + /* scan past 10 mins of error history */ + memset(&arg, 0, sizeof(arg)); + arg.since = j64 - min(j64, j10mins); + ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg); - err_cat = ata_eh_categorize_ering_entry(ent); - if (err_cat == 0) - return 0; + if (arg.nr_errors[2] + arg.nr_errors[3] > 3) + verdict |= ATA_EH_SPDN_NCQ_OFF; + if (arg.nr_errors[1] + arg.nr_errors[2] > 3 || arg.nr_errors[3] > 10) + verdict |= ATA_EH_SPDN_SPEED_DOWN; + /* scan past 3 mins of error history */ memset(&arg, 0, sizeof(arg)); + arg.since = j64 - min(j64, j5mins); + ata_ering_map(&dev->ering, speed_down_verdict_cb, &arg); - j64 = get_jiffies_64(); - if (j64 >= interval) - arg.since = j64 - interval; - else - arg.since = 0; - - ata_ering_map(&dev->ering, speed_down_needed_cb, &arg); + if (arg.nr_errors[1] + arg.nr_errors[2] + arg.nr_errors[3] > 10) + verdict |= ATA_EH_SPDN_FALLBACK_TO_PIO; - return arg.nr_errors[err_cat] > err_limits[err_cat]; + return verdict; } /** @@ -1257,31 +1297,80 @@ static int ata_eh_speed_down_needed(struct ata_device *dev) * Kernel thread context (may sleep). * * RETURNS: - * 0 on success, -errno otherwise + * Determined recovery action. */ -static int ata_eh_speed_down(struct ata_device *dev, int is_io, - unsigned int err_mask) +static unsigned int ata_eh_speed_down(struct ata_device *dev, int is_io, + unsigned int err_mask) { - if (!err_mask) + unsigned int verdict; + unsigned int action = 0; + + /* don't bother if Cat-0 error */ + if (ata_eh_categorize_error(is_io, err_mask) == 0) return 0; /* record error and determine whether speed down is necessary */ ata_ering_record(&dev->ering, is_io, err_mask); + verdict = ata_eh_speed_down_verdict(dev); - if (!ata_eh_speed_down_needed(dev)) - return 0; + /* turn off NCQ? */ + if ((verdict & ATA_EH_SPDN_NCQ_OFF) && + (dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ | + ATA_DFLAG_NCQ_OFF)) == ATA_DFLAG_NCQ) { + dev->flags |= ATA_DFLAG_NCQ_OFF; + ata_dev_printk(dev, KERN_WARNING, + "NCQ disabled due to excessive errors\n"); + goto done; + } - /* speed down SATA link speed if possible */ - if (sata_down_spd_limit(dev->ap) == 0) - return ATA_EH_HARDRESET; + /* speed down? */ + if (verdict & ATA_EH_SPDN_SPEED_DOWN) { + /* speed down SATA link speed if possible */ + if (sata_down_spd_limit(dev->ap) == 0) { + action |= ATA_EH_HARDRESET; + goto done; + } - /* lower transfer mode */ - if (ata_down_xfermask_limit(dev, 0) == 0) - return ATA_EH_SOFTRESET; + /* lower transfer mode */ + if (dev->spdn_cnt < 2) { + static const int dma_dnxfer_sel[] = + { ATA_DNXFER_DMA, ATA_DNXFER_40C }; + static const int pio_dnxfer_sel[] = + { ATA_DNXFER_PIO, ATA_DNXFER_FORCE_PIO0 }; + int sel; + + if (dev->xfer_shift != ATA_SHIFT_PIO) + sel = dma_dnxfer_sel[dev->spdn_cnt]; + else + sel = pio_dnxfer_sel[dev->spdn_cnt]; + + dev->spdn_cnt++; + + if (ata_down_xfermask_limit(dev, sel) == 0) { + action |= ATA_EH_SOFTRESET; + goto done; + } + } + } + + /* Fall back to PIO? Slowing down to PIO is meaningless for + * SATA. Consider it only for PATA. + */ + if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) && + (dev->ap->cbl != ATA_CBL_SATA) && + (dev->xfer_shift != ATA_SHIFT_PIO)) { + if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) { + dev->spdn_cnt = 0; + action |= ATA_EH_SOFTRESET; + goto done; + } + } - ata_dev_printk(dev, KERN_ERR, - "speed down requested but no transfer mode left\n"); return 0; + done: + /* device has been slowed down, blow error history */ + ata_ering_clear(&dev->ering); + return action; } /** @@ -1726,6 +1815,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap, return rc; } +#ifdef CONFIG_PM /** * ata_eh_suspend - handle suspend EH action * @ap: target host port @@ -1883,6 +1973,7 @@ static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev) DPRINTK("EXIT\n"); return 0; } +#endif /* CONFIG_PM */ static int ata_port_nr_enabled(struct ata_port *ap) { @@ -1964,7 +2055,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, { struct ata_eh_context *ehc = &ap->eh_context; struct ata_device *dev; - int down_xfermask, i, rc; + int i, rc; DPRINTK("ENTER\n"); @@ -1993,7 +2084,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, } retry: - down_xfermask = 0; rc = 0; /* if UNLOADING, finish immediately */ @@ -2038,10 +2128,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, /* configure transfer mode if necessary */ if (ehc->i.flags & ATA_EHI_SETMODE) { rc = ata_set_mode(ap, &dev); - if (rc) { - down_xfermask = 1; + if (rc) goto dev_fail; - } ehc->i.flags &= ~ATA_EHI_SETMODE; } @@ -2053,20 +2141,27 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset, goto out; dev_fail: + ehc->tries[dev->devno]--; + switch (rc) { - case -ENODEV: - /* device missing, schedule probing */ - ehc->i.probe_mask |= (1 << dev->devno); case -EINVAL: + /* eeek, something went very wrong, give up */ ehc->tries[dev->devno] = 0; break; + + case -ENODEV: + /* device missing or wrong IDENTIFY data, schedule probing */ + ehc->i.probe_mask |= (1 << dev->devno); + /* give it just one more chance */ + ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1); case -EIO: - sata_down_spd_limit(ap); - default: - ehc->tries[dev->devno]--; - if (down_xfermask && - ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1)) - ehc->tries[dev->devno] = 0; + if (ehc->tries[dev->devno] == 1) { + /* This is the last chance, better to slow + * down than lose it. + */ + sata_down_spd_limit(ap); + ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); + } } if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) { @@ -2181,6 +2276,7 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset, ata_eh_finish(ap); } +#ifdef CONFIG_PM /** * ata_eh_handle_port_suspend - perform port suspend operation * @ap: port to suspend @@ -2296,3 +2392,4 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) } spin_unlock_irqrestore(ap->lock, flags); } +#endif /* CONFIG_PM */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 0009818a430..6cc817a1020 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -333,6 +333,7 @@ int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) scsi_cmd[8] = args[3]; scsi_cmd[10] = args[4]; scsi_cmd[12] = args[5]; + scsi_cmd[13] = args[6] & 0x0f; scsi_cmd[14] = args[0]; /* Good values for timeout and retries? Values below @@ -509,6 +510,7 @@ static void ata_dump_status(unsigned id, struct ata_taskfile *tf) } } +#ifdef CONFIG_PM /** * ata_scsi_device_suspend - suspend ATA device associated with sdev * @sdev: the SCSI device to suspend @@ -633,6 +635,7 @@ int ata_scsi_device_resume(struct scsi_device *sdev) sdev->sdev_gendev.power.power_state = PMSG_ON; return 0; } +#endif /* CONFIG_PM */ /** * ata_to_sense_error - convert ATA error to SCSI error @@ -781,7 +784,7 @@ static void ata_gen_passthru_sense(struct ata_queued_cmd *qc) */ if (qc->err_mask || tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { - ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature, &sb[1], &sb[2], &sb[3], verbose); sb[1] &= 0x0f; } @@ -854,7 +857,7 @@ static void ata_gen_ata_sense(struct ata_queued_cmd *qc) */ if (qc->err_mask || tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { - ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + ata_to_sense_error(qc->ap->print_id, tf->command, tf->feature, &sb[1], &sb[2], &sb[3], verbose); sb[1] &= 0x0f; } @@ -986,29 +989,32 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev; unsigned long flags; - int max_depth; - if (queue_depth < 1) + if (queue_depth < 1 || queue_depth == sdev->queue_depth) return sdev->queue_depth; dev = ata_scsi_find_dev(ap, sdev); if (!dev || !ata_dev_enabled(dev)) return sdev->queue_depth; - max_depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id)); - max_depth = min(ATA_MAX_QUEUE - 1, max_depth); - if (queue_depth > max_depth) - queue_depth = max_depth; - - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth); - + /* NCQ enabled? */ spin_lock_irqsave(ap->lock, flags); - if (queue_depth > 1) - dev->flags &= ~ATA_DFLAG_NCQ_OFF; - else + dev->flags &= ~ATA_DFLAG_NCQ_OFF; + if (queue_depth == 1 || !ata_ncq_enabled(dev)) { dev->flags |= ATA_DFLAG_NCQ_OFF; + queue_depth = 1; + } spin_unlock_irqrestore(ap->lock, flags); + /* limit and apply queue depth */ + queue_depth = min(queue_depth, sdev->host->can_queue); + queue_depth = min(queue_depth, ata_id_queue_depth(dev->id)); + queue_depth = min(queue_depth, ATA_MAX_QUEUE - 1); + + if (sdev->queue_depth == queue_depth) + return -EINVAL; + + scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth); return queue_depth; } @@ -1469,7 +1475,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) } if (need_sense && !ap->ops->error_handler) - ata_dump_status(ap->id, &qc->result_tf); + ata_dump_status(ap->print_id, &qc->result_tf); qc->scsidone(cmd); @@ -1495,11 +1501,9 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) static int ata_scmd_need_defer(struct ata_device *dev, int is_io) { struct ata_port *ap = dev->ap; + int is_ncq = is_io && ata_ncq_enabled(dev); - if (!(dev->flags & ATA_DFLAG_NCQ)) - return 0; - - if (is_io) { + if (is_ncq) { if (!ata_tag_valid(ap->active_tag)) return 0; } else { @@ -2774,7 +2778,7 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap, u8 *scsicmd = cmd->cmnd; DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - ap->id, + ap->print_id, scsidev->channel, scsidev->id, scsidev->lun, scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3], scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7], @@ -3234,7 +3238,7 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host, ata_port_init(ap, host, ent, 0); ap->lock = shost->host_lock; - kfree(ent); + devm_kfree(host->dev, ent); return ap; } EXPORT_SYMBOL_GPL(ata_sas_port_alloc); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 16bc3e35bdd..2ffcca063d8 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -175,7 +175,7 @@ void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) */ void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { - DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); + DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command); iowrite8(tf->command, ap->ioaddr.command_addr); ata_pause(ap); @@ -521,7 +521,7 @@ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc) static int ata_resources_present(struct pci_dev *pdev, int port) { int i; - + /* Check the PCI resources for this channel are enabled */ port = port * 2; for (i = 0; i < 2; i ++) { @@ -531,7 +531,7 @@ static int ata_resources_present(struct pci_dev *pdev, int port) } return 1; } - + /** * ata_pci_init_native_mode - Initialize native-mode driver * @pdev: pci device to be initialized @@ -576,7 +576,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int probe_ent->irq = pdev->irq; probe_ent->irq_flags = IRQF_SHARED; - + /* Discard disabled ports. Some controllers show their unused channels this way */ if (ata_resources_present(pdev, 0) == 0) diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0ad7781d72a..c42671493e8 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -41,6 +41,15 @@ struct ata_scsi_args { enum { /* flags for ata_dev_read_id() */ ATA_READID_POSTRESET = (1 << 0), /* reading ID after reset */ + + /* selector for ata_down_xfermask_limit() */ + ATA_DNXFER_PIO = 0, /* speed down PIO */ + ATA_DNXFER_DMA = 1, /* speed down DMA */ + ATA_DNXFER_40C = 2, /* apply 40c cable limit */ + ATA_DNXFER_FORCE_PIO = 3, /* force PIO */ + ATA_DNXFER_FORCE_PIO0 = 4, /* force PIO0 */ + + ATA_DNXFER_QUIET = (1 << 31), }; extern struct workqueue_struct *ata_aux_wq; @@ -69,7 +78,7 @@ extern int ata_dev_revalidate(struct ata_device *dev, unsigned int flags); extern int ata_dev_configure(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_port *ap); extern int sata_set_spd_needed(struct ata_port *ap); -extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0); +extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev); extern void ata_sg_clean(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); @@ -150,7 +159,5 @@ extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc); /* libata-sff.c */ extern u8 ata_irq_on(struct ata_port *ap); -/* pata_sis.c */ -extern struct ata_port_info sis_info133; #endif /* __LIBATA_H__ */ diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index ab44d18850f..11ea552a58c 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -34,7 +34,7 @@ #include <linux/dmi.h> #define DRV_NAME "pata_ali" -#define DRV_VERSION "0.7.2" +#define DRV_VERSION "0.7.3" /* * Cable special cases @@ -345,8 +345,10 @@ static struct scsi_host_template ali_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; /* @@ -667,11 +669,13 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +#ifdef CONFIG_PM static int ali_reinit_one(struct pci_dev *pdev) { ali_init_chipset(pdev); return ata_pci_device_resume(pdev); } +#endif static const struct pci_device_id ali[] = { { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), }, @@ -685,8 +689,10 @@ static struct pci_driver ali_pci_driver = { .id_table = ali, .probe = ali_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ali_reinit_one, +#endif }; static int __init ali_init(void) diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 619e44b0403..18381762908 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_amd" -#define DRV_VERSION "0.2.7" +#define DRV_VERSION "0.2.8" /** * timing_setup - shared timing computation and load @@ -128,7 +128,7 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse static int amd_pre_reset(struct ata_port *ap) { - static const u32 bitmask[2] = {0x03, 0xC0}; + static const u32 bitmask[2] = {0x03, 0x0C}; static const struct pci_bits amd_enable_bits[] = { { 0x40, 1, 0x02, 0x02 }, { 0x40, 1, 0x01, 0x01 } @@ -247,7 +247,7 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev) */ static int nv_pre_reset(struct ata_port *ap) { - static const u8 bitmask[2] = {0x03, 0xC0}; + static const u8 bitmask[2] = {0x03, 0x0C}; static const struct pci_bits nv_enable_bits[] = { { 0x50, 1, 0x02, 0x02 }, { 0x50, 1, 0x01, 0x01 } @@ -334,8 +334,10 @@ static struct scsi_host_template amd_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations amd33_port_ops = { @@ -663,6 +665,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +#ifdef CONFIG_PM static int amd_reinit_one(struct pci_dev *pdev) { if (pdev->vendor == PCI_VENDOR_ID_AMD) { @@ -679,6 +682,7 @@ static int amd_reinit_one(struct pci_dev *pdev) } return ata_pci_device_resume(pdev); } +#endif static const struct pci_device_id amd[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 }, @@ -708,8 +712,10 @@ static struct pci_driver amd_pci_driver = { .id_table = amd, .probe = amd_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = amd_reinit_one, +#endif }; static int __init amd_init(void) diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index c3eb40c91c8..51d9923be02 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -224,8 +224,10 @@ static struct scsi_host_template atiixp_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations atiixp_port_ops = { @@ -290,8 +292,10 @@ static struct pci_driver atiixp_pci_driver = { .id_table = atiixp, .probe = atiixp_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .resume = ata_pci_device_resume, .suspend = ata_pci_device_suspend, +#endif }; static int __init atiixp_init(void) diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c index da098282b5f..5b13bdd1edc 100644 --- a/drivers/ata/pata_cmd64x.c +++ b/drivers/ata/pata_cmd64x.c @@ -1,5 +1,5 @@ /* - * pata_cmd64x.c - ATI PATA for new ATA layer + * pata_cmd64x.c - CMD64x PATA for new ATA layer * (C) 2005 Red Hat Inc * Alan Cox <alan@redhat.com> * @@ -285,8 +285,10 @@ static struct scsi_host_template cmd64x_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations cmd64x_port_ops = { @@ -479,6 +481,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +#ifdef CONFIG_PM static int cmd64x_reinit_one(struct pci_dev *pdev) { u8 mrdmode; @@ -492,6 +495,7 @@ static int cmd64x_reinit_one(struct pci_dev *pdev) #endif return ata_pci_device_resume(pdev); } +#endif static const struct pci_device_id cmd64x[] = { { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 }, @@ -507,8 +511,10 @@ static struct pci_driver cmd64x_pci_driver = { .id_table = cmd64x, .probe = cmd64x_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = cmd64x_reinit_one, +#endif }; static int __init cmd64x_init(void) diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c index 1ce8fcfd782..7ef834250a4 100644 --- a/drivers/ata/pata_cs5520.c +++ b/drivers/ata/pata_cs5520.c @@ -41,7 +41,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_cs5520" -#define DRV_VERSION "0.6.3" +#define DRV_VERSION "0.6.4" struct pio_clocks { @@ -167,8 +167,10 @@ static struct scsi_host_template cs5520_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations cs5520_port_ops = { @@ -306,9 +308,9 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev) struct ata_host *host = dev_get_drvdata(dev); ata_host_detach(host); - dev_set_drvdata(dev, NULL); } +#ifdef CONFIG_PM /** * cs5520_reinit_one - device resume * @pdev: PCI device @@ -325,6 +327,31 @@ static int cs5520_reinit_one(struct pci_dev *pdev) pci_write_config_byte(pdev, 0x60, pcicfg | 0x40); return ata_pci_device_resume(pdev); } + +/** + * cs5520_pci_device_suspend - device suspend + * @pdev: PCI device + * + * We have to cut and waste bits from the standard method because + * the 5520 is a bit odd and not just a pure ATA device. As a result + * we must not disable it. The needed code is short and this avoids + * chip specific mess in the core code. + */ + +static int cs5520_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + int rc = 0; + + rc = ata_host_suspend(host, mesg); + if (rc) + return rc; + + pci_save_state(pdev); + return 0; +} +#endif /* CONFIG_PM */ + /* For now keep DMA off. We can set it for all but A rev CS5510 once the core ATA code can handle it */ @@ -340,8 +367,10 @@ static struct pci_driver cs5520_pci_driver = { .id_table = pata_cs5520, .probe = cs5520_init_one, .remove = cs5520_remove_one, - .suspend = ata_pci_device_suspend, +#ifdef CONFIG_PM + .suspend = cs5520_pci_device_suspend, .resume = cs5520_reinit_one, +#endif }; static int __init cs5520_init(void) diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c index 3d7b7d87ec6..db63e80e608 100644 --- a/drivers/ata/pata_cs5530.c +++ b/drivers/ata/pata_cs5530.c @@ -35,7 +35,7 @@ #include <linux/dmi.h> #define DRV_NAME "pata_cs5530" -#define DRV_VERSION "0.7.1" +#define DRV_VERSION "0.7.2" static void __iomem *cs5530_port_base(struct ata_port *ap) { @@ -188,8 +188,10 @@ static struct scsi_host_template cs5530_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations cs5530_port_ops = { @@ -376,6 +378,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +#ifdef CONFIG_PM static int cs5530_reinit_one(struct pci_dev *pdev) { /* If we fail on resume we are doomed */ @@ -383,6 +386,7 @@ static int cs5530_reinit_one(struct pci_dev *pdev) BUG(); return ata_pci_device_resume(pdev); } +#endif /* CONFIG_PM */ static const struct pci_device_id cs5530[] = { { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), }, @@ -395,8 +399,10 @@ static struct pci_driver cs5530_pci_driver = { .id_table = cs5530, .probe = cs5530_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = cs5530_reinit_one, +#endif }; static int __init cs5530_init(void) diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c index 17bc693cc51..1572e5c9031 100644 --- a/drivers/ata/pata_cs5535.c +++ b/drivers/ata/pata_cs5535.c @@ -185,8 +185,10 @@ static struct scsi_host_template cs5535_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations cs5535_port_ops = { @@ -270,8 +272,10 @@ static struct pci_driver cs5535_pci_driver = { .id_table = cs5535, .probe = cs5535_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init cs5535_init(void) diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c index 63f48f08763..f69dde5f706 100644 --- a/drivers/ata/pata_cypress.c +++ b/drivers/ata/pata_cypress.c @@ -136,8 +136,10 @@ static struct scsi_host_template cy82c693_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations cy82c693_port_ops = { @@ -206,8 +208,10 @@ static struct pci_driver cy82c693_pci_driver = { .id_table = cy82c693, .probe = cy82c693_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init cy82c693_init(void) diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c index c19b6a8a7dc..dac7a6554f6 100644 --- a/drivers/ata/pata_efar.c +++ b/drivers/ata/pata_efar.c @@ -234,8 +234,10 @@ static struct scsi_host_template efar_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static const struct ata_port_operations efar_ops = { @@ -317,8 +319,10 @@ static struct pci_driver efar_pci_driver = { .id_table = efar_pci_tbl, .probe = efar_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init efar_init(void) diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index 27d724b5eea..baf35f87603 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -27,7 +27,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt366" -#define DRV_VERSION "0.5.3" +#define DRV_VERSION "0.6.0" struct hpt_clock { u8 xfer_speed; @@ -328,8 +328,10 @@ static struct scsi_host_template hpt36x_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; /* @@ -457,12 +459,13 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } +#ifdef CONFIG_PM static int hpt36x_reinit_one(struct pci_dev *dev) { hpt36x_init_chipset(dev); return ata_pci_device_resume(dev); } - +#endif static const struct pci_device_id hpt36x[] = { { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), }, @@ -474,8 +477,10 @@ static struct pci_driver hpt36x_pci_driver = { .id_table = hpt36x, .probe = hpt36x_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = hpt36x_reinit_one, +#endif }; static int __init hpt36x_init(void) diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c index 4ffc392052c..f331eeeafa0 100644 --- a/drivers/ata/pata_hpt37x.c +++ b/drivers/ata/pata_hpt37x.c @@ -25,7 +25,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt37x" -#define DRV_VERSION "0.5.2" +#define DRV_VERSION "0.6.0" struct hpt_clock { u8 xfer_speed; diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index 483ce7c12c9..813485c8526 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -119,8 +119,10 @@ static struct scsi_host_template hpt3x3_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations hpt3x3_port_ops = { @@ -206,11 +208,13 @@ static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id) return ata_pci_init_one(dev, port_info, 2); } +#ifdef CONFIG_PM static int hpt3x3_reinit_one(struct pci_dev *dev) { hpt3x3_init_chipset(dev); return ata_pci_device_resume(dev); } +#endif static const struct pci_device_id hpt3x3[] = { { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), }, @@ -223,8 +227,10 @@ static struct pci_driver hpt3x3_pci_driver = { .id_table = hpt3x3, .probe = hpt3x3_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = hpt3x3_reinit_one, +#endif }; static int __init hpt3x3_init(void) diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c index 1bf5ec18b2e..1a61cc89174 100644 --- a/drivers/ata/pata_isapnp.c +++ b/drivers/ata/pata_isapnp.c @@ -17,7 +17,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_isapnp" -#define DRV_VERSION "0.1.5" +#define DRV_VERSION "0.2.0" static struct scsi_host_template isapnp_sht = { .module = THIS_MODULE, @@ -128,7 +128,6 @@ static void isapnp_remove_one(struct pnp_dev *idev) struct ata_host *host = dev_get_drvdata(dev); ata_host_detach(host); - dev_set_drvdata(dev, NULL); } static struct pnp_device_id isapnp_devices[] = { diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c index 7eac869dfcd..ea734701555 100644 --- a/drivers/ata/pata_it8213.c +++ b/drivers/ata/pata_it8213.c @@ -246,8 +246,10 @@ static struct scsi_host_template it8213_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static const struct ata_port_operations it8213_ops = { @@ -330,8 +332,10 @@ static struct pci_driver it8213_pci_driver = { .id_table = it8213_pci_tbl, .probe = it8213_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init it8213_init(void) diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index 73394c75be4..35ecb2ba067 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -80,7 +80,7 @@ #define DRV_NAME "pata_it821x" -#define DRV_VERSION "0.3.3" +#define DRV_VERSION "0.3.4" struct it821x_dev { @@ -503,10 +503,12 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused /* We do need the right mode information for DMA or PIO and this comes from the current configuration flags */ if (dma_enabled & (1 << (5 + i))) { + ata_dev_printk(dev, KERN_INFO, "configured for DMA\n"); dev->xfer_mode = XFER_MW_DMA_0; dev->xfer_shift = ATA_SHIFT_MWDMA; dev->flags &= ~ATA_DFLAG_PIO; } else { + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; dev->flags |= ATA_DFLAG_PIO; @@ -644,8 +646,10 @@ static struct scsi_host_template it821x_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations it821x_smart_port_ops = { @@ -778,6 +782,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +#ifdef CONFIG_PM static int it821x_reinit_one(struct pci_dev *pdev) { /* Resume - turn raid back off if need be */ @@ -785,6 +790,7 @@ static int it821x_reinit_one(struct pci_dev *pdev) it821x_disable_raid(pdev); return ata_pci_device_resume(pdev); } +#endif static const struct pci_device_id it821x[] = { { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), }, @@ -798,8 +804,10 @@ static struct pci_driver it821x_pci_driver = { .id_table = it821x, .probe = it821x_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = it821x_reinit_one, +#endif }; static int __init it821x_init(void) diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c index 3222ac7b945..9a0523b5c94 100644 --- a/drivers/ata/pata_ixp4xx_cf.c +++ b/drivers/ata/pata_ixp4xx_cf.c @@ -23,15 +23,16 @@ #include <scsi/scsi_host.h> #define DRV_NAME "pata_ixp4xx_cf" -#define DRV_VERSION "0.1.1ac1" +#define DRV_VERSION "0.1.2" -static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device *adev) +static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error) { int i; for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; - if (ata_dev_enabled(dev)) { + if (ata_dev_ready(dev)) { + ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n"); dev->pio_mode = XFER_PIO_0; dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 7a635dd326f..43763c99ea0 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -137,6 +137,10 @@ static struct scsi_host_template jmicron_sht = { .slave_destroy = ata_scsi_slave_destroy, /* Use standard CHS mapping rules */ .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM + .suspend = ata_scsi_device_suspend, + .resume = ata_scsi_device_resume, +#endif }; static const struct ata_port_operations jmicron_ops = { @@ -202,49 +206,20 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i }; struct ata_port_info *port_info[2] = { &info, &info }; - u32 reg; - - /* PATA controller is fn 1, AHCI is fn 0 */ - if (id->driver_data != 368 && PCI_FUNC(pdev->devfn) != 1) - return -ENODEV; - - /* The 365/66 have two PATA channels, redirect the second */ - if (id->driver_data == 365 || id->driver_data == 366) { - pci_read_config_dword(pdev, 0x80, ®); - reg |= (1 << 24); /* IDE1 to PATA IDE secondary */ - pci_write_config_dword(pdev, 0x80, reg); - } - return ata_pci_init_one(pdev, port_info, 2); } -static int jmicron_reinit_one(struct pci_dev *pdev) -{ - u32 reg; - - switch(pdev->device) { - case PCI_DEVICE_ID_JMICRON_JMB368: - break; - case PCI_DEVICE_ID_JMICRON_JMB365: - case PCI_DEVICE_ID_JMICRON_JMB366: - /* Restore mapping or disks swap and boy does it get ugly */ - pci_read_config_dword(pdev, 0x80, ®); - reg |= (1 << 24); /* IDE1 to PATA IDE secondary */ - pci_write_config_dword(pdev, 0x80, reg); - /* Fall through */ - default: - /* Make sure AHCI is turned back on */ - pci_write_config_byte(pdev, 0x41, 0xa1); - } - return ata_pci_device_resume(pdev); -} - static const struct pci_device_id jmicron_pci_tbl[] = { - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361}, - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363}, - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365}, - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366}, - { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368}, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 }, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 }, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 }, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 }, + { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, + PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 368 }, { } /* terminate list */ }; @@ -254,8 +229,10 @@ static struct pci_driver jmicron_pci_driver = { .id_table = jmicron_pci_tbl, .probe = jmicron_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, - .resume = jmicron_reinit_one, + .resume = ata_pci_device_resume, +#endif }; static int __init jmicron_init(void) diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 98c1fee4b30..86fbcd6a742 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -64,12 +64,12 @@ #include <linux/platform_device.h> #define DRV_NAME "pata_legacy" -#define DRV_VERSION "0.5.3" +#define DRV_VERSION "0.5.4" #define NR_HOST 6 static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 }; -static int legacy_irq[NR_HOST] = { 15, 14, 11, 10, 8, 12 }; +static int legacy_irq[NR_HOST] = { 14, 15, 11, 10, 8, 12 }; struct legacy_data { unsigned long timing; @@ -186,7 +186,10 @@ static struct ata_port_operations legacy_port_ops = { .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -298,7 +301,10 @@ static struct ata_port_operations pdc20230_port_ops = { .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -350,7 +356,10 @@ static struct ata_port_operations ht6560a_port_ops = { .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -413,7 +422,10 @@ static struct ata_port_operations ht6560b_port_ops = { .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -531,7 +543,10 @@ static struct ata_port_operations opti82c611a_port_ops = { .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, @@ -661,7 +676,10 @@ static struct ata_port_operations opti82c46x_port_ops = { .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .qc_prep = ata_qc_prep, .qc_issue = opti82c46x_qc_issue_prot, diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 13a70ac6f1d..6dd7c4ef3e6 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -103,8 +103,10 @@ static struct scsi_host_template marvell_sht = { .slave_destroy = ata_scsi_slave_destroy, /* Use standard CHS mapping rules */ .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static const struct ata_port_operations marvell_ops = { @@ -199,8 +201,10 @@ static struct pci_driver marvell_pci_driver = { .id_table = marvell_pci_tbl, .probe = marvell_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init marvell_init(void) diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c index 29e1809e5ec..f5d88729ca7 100644 --- a/drivers/ata/pata_mpc52xx.c +++ b/drivers/ata/pata_mpc52xx.c @@ -280,6 +280,10 @@ static struct scsi_host_template mpc52xx_ata_sht = { .dma_boundary = ATA_DMA_BOUNDARY, .slave_configure = ata_scsi_slave_config, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM + .suspend = ata_scsi_device_suspend, + .resume = ata_scsi_device_resume, +#endif }; static struct ata_port_operations mpc52xx_ata_port_ops = { diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index f2e7115f7ab..4abe45ac19a 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -165,8 +165,10 @@ static struct scsi_host_template mpiix_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations mpiix_port_ops = { @@ -270,8 +272,10 @@ static struct pci_driver mpiix_pci_driver = { .id_table = mpiix, .probe = mpiix_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init mpiix_init(void) diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c index e8393e19be4..38f99b38a5e 100644 --- a/drivers/ata/pata_netcell.c +++ b/drivers/ata/pata_netcell.c @@ -63,8 +63,10 @@ static struct scsi_host_template netcell_sht = { .slave_destroy = ata_scsi_slave_destroy, /* Use standard CHS mapping rules */ .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static const struct ata_port_operations netcell_ops = { @@ -153,8 +155,10 @@ static struct pci_driver netcell_pci_driver = { .id_table = netcell_pci_tbl, .probe = netcell_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init netcell_init(void) diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c index 3d1fa487c48..9944a28daa9 100644 --- a/drivers/ata/pata_ns87410.c +++ b/drivers/ata/pata_ns87410.c @@ -157,8 +157,10 @@ static struct scsi_host_template ns87410_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations ns87410_port_ops = { @@ -212,8 +214,10 @@ static struct pci_driver ns87410_pci_driver = { .id_table = ns87410, .probe = ns87410_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init ns87410_init(void) diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c index 45215aa05e7..da68cd19efd 100644 --- a/drivers/ata/pata_oldpiix.c +++ b/drivers/ata/pata_oldpiix.c @@ -25,7 +25,7 @@ #include <linux/ata.h> #define DRV_NAME "pata_oldpiix" -#define DRV_VERSION "0.5.3" +#define DRV_VERSION "0.5.4" /** * oldpiix_pre_reset - probe begin @@ -209,10 +209,9 @@ static unsigned int oldpiix_qc_issue_prot(struct ata_queued_cmd *qc) struct ata_device *adev = qc->dev; if (adev != ap->private_data) { + oldpiix_set_piomode(ap, adev); if (adev->dma_mode) oldpiix_set_dmamode(ap, adev); - else if (adev->pio_mode) - oldpiix_set_piomode(ap, adev); } return ata_qc_issue_prot(qc); } @@ -234,8 +233,10 @@ static struct scsi_host_template oldpiix_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static const struct ata_port_operations oldpiix_pata_ops = { @@ -317,8 +318,10 @@ static struct pci_driver oldpiix_pci_driver = { .id_table = oldpiix_pci_tbl, .probe = oldpiix_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init oldpiix_init(void) diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c index da1aa148b37..3fd3a35c224 100644 --- a/drivers/ata/pata_opti.c +++ b/drivers/ata/pata_opti.c @@ -34,7 +34,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_opti" -#define DRV_VERSION "0.2.7" +#define DRV_VERSION "0.2.8" enum { READ_REG = 0, /* index of Read cycle timing register */ @@ -179,8 +179,10 @@ static struct scsi_host_template opti_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations opti_port_ops = { @@ -244,8 +246,10 @@ static struct pci_driver opti_pci_driver = { .id_table = opti, .probe = opti_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init opti_init(void) diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c index d80b36e209c..9764907e8a1 100644 --- a/drivers/ata/pata_optidma.c +++ b/drivers/ata/pata_optidma.c @@ -33,7 +33,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_optidma" -#define DRV_VERSION "0.2.3" +#define DRV_VERSION "0.2.4" enum { READ_REG = 0, /* index of Read cycle timing register */ @@ -360,8 +360,10 @@ static struct scsi_host_template optidma_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations optidma_port_ops = { @@ -524,8 +526,10 @@ static struct pci_driver optidma_pci_driver = { .id_table = optidma, .probe = optidma_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init optidma_init(void) diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 36468ec6454..103720f873c 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -42,7 +42,7 @@ #define DRV_NAME "pata_pcmcia" -#define DRV_VERSION "0.2.11" +#define DRV_VERSION "0.3.0" /* * Private data structure to glue stuff together @@ -308,7 +308,6 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev) if (info->ndev) { struct ata_host *host = dev_get_drvdata(dev); ata_host_detach(host); - dev_set_drvdata(dev, NULL); } info->ndev = 0; pdev->priv = NULL; @@ -320,14 +319,17 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev) static struct pcmcia_device_id pcmcia_devices[] = { PCMCIA_DEVICE_FUNC_ID(4), PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ + PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */ + PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */ PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), - PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), + PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */ PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */ PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */ + PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */ + PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */ PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74), PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9), diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c index 61537873d28..93bcdadb7be 100644 --- a/drivers/ata/pata_pdc2027x.c +++ b/drivers/ata/pata_pdc2027x.c @@ -35,7 +35,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_pdc2027x" -#define DRV_VERSION "0.74-ac5" +#define DRV_VERSION "0.8" #undef PDC_DEBUG #ifdef PDC_DEBUG diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 6dd63413a52..acdc52cbe38 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c @@ -2,13 +2,14 @@ * pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer * (C) 2005 Red Hat Inc * Alan Cox <alan@redhat.com> + * (C) 2007 Bartlomiej Zolnierkiewicz * * Based in part on linux/drivers/ide/pci/pdc202xx_old.c * * First cut with LBA48/ATAPI * * TODO: - * Channel interlock/reset on both required ? + * Channel interlock/reset on both required */ #include <linux/kernel.h> @@ -21,7 +22,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_pdc202xx_old" -#define DRV_VERSION "0.2.3" +#define DRV_VERSION "0.4.0" /** * pdc2024x_pre_reset - probe begin @@ -76,7 +77,7 @@ static void pdc2026x_error_handler(struct ata_port *ap) static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); - int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; + int port = 0x60 + 8 * ap->port_no + 4 * adev->devno; static u16 pio_timing[5] = { 0x0913, 0x050C , 0x0308, 0x0206, 0x0104 }; @@ -85,7 +86,7 @@ static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *a pci_read_config_byte(pdev, port, &r_ap); pci_read_config_byte(pdev, port + 1, &r_bp); r_ap &= ~0x3F; /* Preserve ERRDY_EN, SYNC_IN */ - r_bp &= ~0x07; + r_bp &= ~0x1F; r_ap |= (pio_timing[pio] >> 8); r_bp |= (pio_timing[pio] & 0xFF); @@ -123,7 +124,7 @@ static void pdc202xx_set_piomode(struct ata_port *ap, struct ata_device *adev) static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); - int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; + int port = 0x60 + 8 * ap->port_no + 4 * adev->devno; static u8 udma_timing[6][2] = { { 0x60, 0x03 }, /* 33 Mhz Clock */ { 0x40, 0x02 }, @@ -132,12 +133,17 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) { 0x20, 0x01 }, { 0x20, 0x01 } }; + static u8 mdma_timing[3][2] = { + { 0x60, 0x03 }, + { 0x60, 0x04 }, + { 0xe0, 0x0f }, + }; u8 r_bp, r_cp; pci_read_config_byte(pdev, port + 1, &r_bp); pci_read_config_byte(pdev, port + 2, &r_cp); - r_bp &= ~0xF0; + r_bp &= ~0xE0; r_cp &= ~0x0F; if (adev->dma_mode >= XFER_UDMA_0) { @@ -147,8 +153,8 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) } else { int speed = adev->dma_mode - XFER_MW_DMA_0; - r_bp |= 0x60; - r_cp |= (5 - speed); + r_bp |= mdma_timing[speed][0]; + r_cp |= mdma_timing[speed][1]; } pci_write_config_byte(pdev, port + 1, r_bp); pci_write_config_byte(pdev, port + 2, r_cp); @@ -267,8 +273,10 @@ static struct scsi_host_template pdc202xx_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations pdc2024x_port_ops = { @@ -399,8 +407,10 @@ static struct pci_driver pdc202xx_pci_driver = { .id_table = pdc202xx, .probe = pdc202xx_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init pdc202xx_init(void) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 479a326114e..4b82a5435a4 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -42,6 +42,7 @@ static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unuse dev->pio_mode = dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; dev->flags |= ATA_DFLAG_PIO; + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); } } return 0; @@ -227,7 +228,6 @@ static int __devexit pata_platform_remove(struct platform_device *pdev) struct ata_host *host = dev_get_drvdata(dev); ata_host_detach(host); - dev_set_drvdata(dev, NULL); return 0; } diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 4362141976a..c3810012f3f 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -26,7 +26,7 @@ #include <linux/platform_device.h> #define DRV_NAME "pata_qdi" -#define DRV_VERSION "0.2.4" +#define DRV_VERSION "0.3.0" #define NR_HOST 4 /* Two 6580s */ @@ -363,7 +363,8 @@ static __init int qdi_init(void) release_region(port, 2); continue; } - ct += qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04); + if (qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04) == 0) + ct++; } if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) { /* QD6580: dual channel */ @@ -375,11 +376,14 @@ static __init int qdi_init(void) res = inb(port + 3); if (res & 1) { /* Single channel mode */ - ct += qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04); + if (qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04)) + ct++; } else { /* Dual channel mode */ - ct += qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04); - ct += qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04); + if (qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04) == 0) + ct++; + if (qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04) == 0) + ct++; } } } diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c index 0d1e571ef63..9a9132c9e33 100644 --- a/drivers/ata/pata_radisys.c +++ b/drivers/ata/pata_radisys.c @@ -228,8 +228,10 @@ static struct scsi_host_template radisys_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static const struct ata_port_operations radisys_pata_ops = { @@ -312,8 +314,10 @@ static struct pci_driver radisys_pci_driver = { .id_table = radisys_pci_tbl, .probe = radisys_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init radisys_init(void) diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c index 71a2bac09e0..f522daa2a6a 100644 --- a/drivers/ata/pata_rz1000.c +++ b/drivers/ata/pata_rz1000.c @@ -71,6 +71,7 @@ static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused) dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; dev->flags |= ATA_DFLAG_PIO; + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); } } return 0; @@ -93,8 +94,10 @@ static struct scsi_host_template rz1000_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations rz1000_port_ops = { @@ -177,6 +180,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en return -ENODEV; } +#ifdef CONFIG_PM static int rz1000_reinit_one(struct pci_dev *pdev) { /* If this fails on resume (which is a "cant happen" case), we @@ -185,6 +189,7 @@ static int rz1000_reinit_one(struct pci_dev *pdev) panic("rz1000 fifo"); return ata_pci_device_resume(pdev); } +#endif static const struct pci_device_id pata_rz1000[] = { { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), }, @@ -198,8 +203,10 @@ static struct pci_driver rz1000_pci_driver = { .id_table = pata_rz1000, .probe = rz1000_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = rz1000_reinit_one, +#endif }; static int __init rz1000_init(void) diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c index 58e42fbd14f..93b3ed0f9e8 100644 --- a/drivers/ata/pata_sc1200.c +++ b/drivers/ata/pata_sc1200.c @@ -194,8 +194,10 @@ static struct scsi_host_template sc1200_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations sc1200_port_ops = { @@ -210,7 +212,10 @@ static struct ata_port_operations sc1200_port_ops = { .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, .error_handler = ata_bmdma_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .bmdma_setup = ata_bmdma_setup, .bmdma_start = ata_bmdma_start, @@ -266,8 +271,10 @@ static struct pci_driver sc1200_pci_driver = { .id_table = sc1200, .probe = sc1200_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init sc1200_init(void) diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c new file mode 100644 index 00000000000..f3ed141fdc0 --- /dev/null +++ b/drivers/ata/pata_scc.c @@ -0,0 +1,1230 @@ +/* + * Support for IDE interfaces on Celleb platform + * + * (C) Copyright 2006 TOSHIBA CORPORATION + * + * This code is based on drivers/ata/ata_piix.c: + * Copyright 2003-2005 Red Hat Inc + * Copyright 2003-2005 Jeff Garzik + * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer + * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2003 Red Hat Inc <alan@redhat.com> + * + * and drivers/ata/ahci.c: + * Copyright 2004-2005 Red Hat, Inc. + * + * and drivers/ata/libata-core.c: + * Copyright 2003-2004 Red Hat, Inc. All rights reserved. + * Copyright 2003-2004 Jeff Garzik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/blkdev.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <scsi/scsi_host.h> +#include <linux/libata.h> + +#define DRV_NAME "pata_scc" +#define DRV_VERSION "0.1" + +#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4 + +/* PCI BARs */ +#define SCC_CTRL_BAR 0 +#define SCC_BMID_BAR 1 + +/* offset of CTRL registers */ +#define SCC_CTL_PIOSHT 0x000 +#define SCC_CTL_PIOCT 0x004 +#define SCC_CTL_MDMACT 0x008 +#define SCC_CTL_MCRCST 0x00C +#define SCC_CTL_SDMACT 0x010 +#define SCC_CTL_SCRCST 0x014 +#define SCC_CTL_UDENVT 0x018 +#define SCC_CTL_TDVHSEL 0x020 +#define SCC_CTL_MODEREG 0x024 +#define SCC_CTL_ECMODE 0xF00 +#define SCC_CTL_MAEA0 0xF50 +#define SCC_CTL_MAEC0 0xF54 +#define SCC_CTL_CCKCTRL 0xFF0 + +/* offset of BMID registers */ +#define SCC_DMA_CMD 0x000 +#define SCC_DMA_STATUS 0x004 +#define SCC_DMA_TABLE_OFS 0x008 +#define SCC_DMA_INTMASK 0x010 +#define SCC_DMA_INTST 0x014 +#define SCC_DMA_PTERADD 0x018 +#define SCC_REG_CMD_ADDR 0x020 +#define SCC_REG_DATA 0x000 +#define SCC_REG_ERR 0x004 +#define SCC_REG_FEATURE 0x004 +#define SCC_REG_NSECT 0x008 +#define SCC_REG_LBAL 0x00C +#define SCC_REG_LBAM 0x010 +#define SCC_REG_LBAH 0x014 +#define SCC_REG_DEVICE 0x018 +#define SCC_REG_STATUS 0x01C +#define SCC_REG_CMD 0x01C +#define SCC_REG_ALTSTATUS 0x020 + +/* register value */ +#define TDVHSEL_MASTER 0x00000001 +#define TDVHSEL_SLAVE 0x00000004 + +#define MODE_JCUSFEN 0x00000080 + +#define ECMODE_VALUE 0x01 + +#define CCKCTRL_ATARESET 0x00040000 +#define CCKCTRL_BUFCNT 0x00020000 +#define CCKCTRL_CRST 0x00010000 +#define CCKCTRL_OCLKEN 0x00000100 +#define CCKCTRL_ATACLKOEN 0x00000002 +#define CCKCTRL_LCLKEN 0x00000001 + +#define QCHCD_IOS_SS 0x00000001 + +#define QCHSD_STPDIAG 0x00020000 + +#define INTMASK_MSK 0xD1000012 +#define INTSTS_SERROR 0x80000000 +#define INTSTS_PRERR 0x40000000 +#define INTSTS_RERR 0x10000000 +#define INTSTS_ICERR 0x01000000 +#define INTSTS_BMSINT 0x00000010 +#define INTSTS_BMHE 0x00000008 +#define INTSTS_IOIRQS 0x00000004 +#define INTSTS_INTRQ 0x00000002 +#define INTSTS_ACTEINT 0x00000001 + + +/* PIO transfer mode table */ +/* JCHST */ +static const unsigned long JCHSTtbl[2][7] = { + {0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */ + {0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */ +}; + +/* JCHHT */ +static const unsigned long JCHHTtbl[2][7] = { + {0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */ + {0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */ +}; + +/* JCHCT */ +static const unsigned long JCHCTtbl[2][7] = { + {0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */ + {0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */ +}; + +/* DMA transfer mode table */ +/* JCHDCTM/JCHDCTS */ +static const unsigned long JCHDCTxtbl[2][7] = { + {0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */ + {0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */ +}; + +/* JCSTWTM/JCSTWTS */ +static const unsigned long JCSTWTxtbl[2][7] = { + {0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */ + {0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ +}; + +/* JCTSS */ +static const unsigned long JCTSStbl[2][7] = { + {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */ + {0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */ +}; + +/* JCENVT */ +static const unsigned long JCENVTtbl[2][7] = { + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */ + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */ +}; + +/* JCACTSELS/JCACTSELM */ +static const unsigned long JCACTSELtbl[2][7] = { + {0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */ +}; + +static const struct pci_device_id scc_pci_tbl[] = { + {PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { } /* terminate list */ +}; + +/** + * scc_set_piomode - Initialize host controller PATA PIO timings + * @ap: Port whose timings we are configuring + * @adev: um + * + * Set PIO mode for device. + * + * LOCKING: + * None (inherited from caller). + */ + +static void scc_set_piomode (struct ata_port *ap, struct ata_device *adev) +{ + unsigned int pio = adev->pio_mode - XFER_PIO_0; + void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR]; + void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL; + void __iomem *piosht_port = ctrl_base + SCC_CTL_PIOSHT; + void __iomem *pioct_port = ctrl_base + SCC_CTL_PIOCT; + unsigned long reg; + int offset; + + reg = in_be32(cckctrl_port); + if (reg & CCKCTRL_ATACLKOEN) + offset = 1; /* 133MHz */ + else + offset = 0; /* 100MHz */ + + reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio]; + out_be32(piosht_port, reg); + reg = JCHCTtbl[offset][pio]; + out_be32(pioct_port, reg); +} + +/** + * scc_set_dmamode - Initialize host controller PATA DMA timings + * @ap: Port whose timings we are configuring + * @adev: um + * @udma: udma mode, 0 - 6 + * + * Set UDMA mode for device. + * + * LOCKING: + * None (inherited from caller). + */ + +static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev) +{ + unsigned int udma = adev->dma_mode; + unsigned int is_slave = (adev->devno != 0); + u8 speed = udma; + void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR]; + void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL; + void __iomem *mdmact_port = ctrl_base + SCC_CTL_MDMACT; + void __iomem *mcrcst_port = ctrl_base + SCC_CTL_MCRCST; + void __iomem *sdmact_port = ctrl_base + SCC_CTL_SDMACT; + void __iomem *scrcst_port = ctrl_base + SCC_CTL_SCRCST; + void __iomem *udenvt_port = ctrl_base + SCC_CTL_UDENVT; + void __iomem *tdvhsel_port = ctrl_base + SCC_CTL_TDVHSEL; + int offset, idx; + + if (in_be32(cckctrl_port) & CCKCTRL_ATACLKOEN) + offset = 1; /* 133MHz */ + else + offset = 0; /* 100MHz */ + + if (speed >= XFER_UDMA_0) + idx = speed - XFER_UDMA_0; + else + return; + + if (is_slave) { + out_be32(sdmact_port, JCHDCTxtbl[offset][idx]); + out_be32(scrcst_port, JCSTWTxtbl[offset][idx]); + out_be32(tdvhsel_port, + (in_be32(tdvhsel_port) & ~TDVHSEL_SLAVE) | (JCACTSELtbl[offset][idx] << 2)); + } else { + out_be32(mdmact_port, JCHDCTxtbl[offset][idx]); + out_be32(mcrcst_port, JCSTWTxtbl[offset][idx]); + out_be32(tdvhsel_port, + (in_be32(tdvhsel_port) & ~TDVHSEL_MASTER) | JCACTSELtbl[offset][idx]); + } + out_be32(udenvt_port, + JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]); +} + +/** + * scc_tf_load - send taskfile registers to host controller + * @ap: Port to which output is sent + * @tf: ATA taskfile register set + * + * Note: Original code is ata_tf_load(). + */ + +static void scc_tf_load (struct ata_port *ap, const struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + if (tf->ctl != ap->last_ctl) { + out_be32(ioaddr->ctl_addr, tf->ctl); + ap->last_ctl = tf->ctl; + ata_wait_idle(ap); + } + + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + out_be32(ioaddr->feature_addr, tf->hob_feature); + out_be32(ioaddr->nsect_addr, tf->hob_nsect); + out_be32(ioaddr->lbal_addr, tf->hob_lbal); + out_be32(ioaddr->lbam_addr, tf->hob_lbam); + out_be32(ioaddr->lbah_addr, tf->hob_lbah); + VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n", + tf->hob_feature, + tf->hob_nsect, + tf->hob_lbal, + tf->hob_lbam, + tf->hob_lbah); + } + + if (is_addr) { + out_be32(ioaddr->feature_addr, tf->feature); + out_be32(ioaddr->nsect_addr, tf->nsect); + out_be32(ioaddr->lbal_addr, tf->lbal); + out_be32(ioaddr->lbam_addr, tf->lbam); + out_be32(ioaddr->lbah_addr, tf->lbah); + VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n", + tf->feature, + tf->nsect, + tf->lbal, + tf->lbam, + tf->lbah); + } + + if (tf->flags & ATA_TFLAG_DEVICE) { + out_be32(ioaddr->device_addr, tf->device); + VPRINTK("device 0x%X\n", tf->device); + } + + ata_wait_idle(ap); +} + +/** + * scc_check_status - Read device status reg & clear interrupt + * @ap: port where the device is + * + * Note: Original code is ata_check_status(). + */ + +static u8 scc_check_status (struct ata_port *ap) +{ + return in_be32(ap->ioaddr.status_addr); +} + +/** + * scc_tf_read - input device's ATA taskfile shadow registers + * @ap: Port from which input is read + * @tf: ATA taskfile register set for storing input + * + * Note: Original code is ata_tf_read(). + */ + +static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + tf->command = scc_check_status(ap); + tf->feature = in_be32(ioaddr->error_addr); + tf->nsect = in_be32(ioaddr->nsect_addr); + tf->lbal = in_be32(ioaddr->lbal_addr); + tf->lbam = in_be32(ioaddr->lbam_addr); + tf->lbah = in_be32(ioaddr->lbah_addr); + tf->device = in_be32(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + out_be32(ioaddr->ctl_addr, tf->ctl | ATA_HOB); + tf->hob_feature = in_be32(ioaddr->error_addr); + tf->hob_nsect = in_be32(ioaddr->nsect_addr); + tf->hob_lbal = in_be32(ioaddr->lbal_addr); + tf->hob_lbam = in_be32(ioaddr->lbam_addr); + tf->hob_lbah = in_be32(ioaddr->lbah_addr); + } +} + +/** + * scc_exec_command - issue ATA command to host controller + * @ap: port to which command is being issued + * @tf: ATA taskfile register set + * + * Note: Original code is ata_exec_command(). + */ + +static void scc_exec_command (struct ata_port *ap, + const struct ata_taskfile *tf) +{ + DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command); + + out_be32(ap->ioaddr.command_addr, tf->command); + ata_pause(ap); +} + +/** + * scc_check_altstatus - Read device alternate status reg + * @ap: port where the device is + */ + +static u8 scc_check_altstatus (struct ata_port *ap) +{ + return in_be32(ap->ioaddr.altstatus_addr); +} + +/** + * scc_std_dev_select - Select device 0/1 on ATA bus + * @ap: ATA channel to manipulate + * @device: ATA device (numbered from zero) to select + * + * Note: Original code is ata_std_dev_select(). + */ + +static void scc_std_dev_select (struct ata_port *ap, unsigned int device) +{ + u8 tmp; + + if (device == 0) + tmp = ATA_DEVICE_OBS; + else + tmp = ATA_DEVICE_OBS | ATA_DEV1; + + out_be32(ap->ioaddr.device_addr, tmp); + ata_pause(ap); +} + +/** + * scc_bmdma_setup - Set up PCI IDE BMDMA transaction + * @qc: Info associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_setup(). + */ + +static void scc_bmdma_setup (struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); + u8 dmactl; + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + /* load PRD table addr */ + out_be32(mmio + SCC_DMA_TABLE_OFS, ap->prd_dma); + + /* specify data direction, triple-check start bit is clear */ + dmactl = in_be32(mmio + SCC_DMA_CMD); + dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); + if (!rw) + dmactl |= ATA_DMA_WR; + out_be32(mmio + SCC_DMA_CMD, dmactl); + + /* issue r/w command */ + ap->ops->exec_command(ap, &qc->tf); +} + +/** + * scc_bmdma_start - Start a PCI IDE BMDMA transaction + * @qc: Info associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_start(). + */ + +static void scc_bmdma_start (struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + u8 dmactl; + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + /* start host DMA transaction */ + dmactl = in_be32(mmio + SCC_DMA_CMD); + out_be32(mmio + SCC_DMA_CMD, dmactl | ATA_DMA_START); +} + +/** + * scc_devchk - PATA device presence detection + * @ap: ATA channel to examine + * @device: Device to examine (starting at zero) + * + * Note: Original code is ata_devchk(). + */ + +static unsigned int scc_devchk (struct ata_port *ap, + unsigned int device) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 nsect, lbal; + + ap->ops->dev_select(ap, device); + + out_be32(ioaddr->nsect_addr, 0x55); + out_be32(ioaddr->lbal_addr, 0xaa); + + out_be32(ioaddr->nsect_addr, 0xaa); + out_be32(ioaddr->lbal_addr, 0x55); + + out_be32(ioaddr->nsect_addr, 0x55); + out_be32(ioaddr->lbal_addr, 0xaa); + + nsect = in_be32(ioaddr->nsect_addr); + lbal = in_be32(ioaddr->lbal_addr); + + if ((nsect == 0x55) && (lbal == 0xaa)) + return 1; /* we found a device */ + + return 0; /* nothing found */ +} + +/** + * scc_bus_post_reset - PATA device post reset + * + * Note: Original code is ata_bus_post_reset(). + */ + +static void scc_bus_post_reset (struct ata_port *ap, unsigned int devmask) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int dev0 = devmask & (1 << 0); + unsigned int dev1 = devmask & (1 << 1); + unsigned long timeout; + + /* if device 0 was found in ata_devchk, wait for its + * BSY bit to clear + */ + if (dev0) + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + + /* if device 1 was found in ata_devchk, wait for + * register access, then wait for BSY to clear + */ + timeout = jiffies + ATA_TMOUT_BOOT; + while (dev1) { + u8 nsect, lbal; + + ap->ops->dev_select(ap, 1); + nsect = in_be32(ioaddr->nsect_addr); + lbal = in_be32(ioaddr->lbal_addr); + if ((nsect == 1) && (lbal == 1)) + break; + if (time_after(jiffies, timeout)) { + dev1 = 0; + break; + } + msleep(50); /* give drive a breather */ + } + if (dev1) + ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT); + + /* is all this really necessary? */ + ap->ops->dev_select(ap, 0); + if (dev1) + ap->ops->dev_select(ap, 1); + if (dev0) + ap->ops->dev_select(ap, 0); +} + +/** + * scc_bus_softreset - PATA device software reset + * + * Note: Original code is ata_bus_softreset(). + */ + +static unsigned int scc_bus_softreset (struct ata_port *ap, + unsigned int devmask) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + DPRINTK("ata%u: bus reset via SRST\n", ap->print_id); + + /* software reset. causes dev0 to be selected */ + out_be32(ioaddr->ctl_addr, ap->ctl); + udelay(20); + out_be32(ioaddr->ctl_addr, ap->ctl | ATA_SRST); + udelay(20); + out_be32(ioaddr->ctl_addr, ap->ctl); + + /* spec mandates ">= 2ms" before checking status. + * We wait 150ms, because that was the magic delay used for + * ATAPI devices in Hale Landis's ATADRVR, for the period of time + * between when the ATA command register is written, and then + * status is checked. Because waiting for "a while" before + * checking status is fine, post SRST, we perform this magic + * delay here as well. + * + * Old drivers/ide uses the 2mS rule and then waits for ready + */ + msleep(150); + + /* Before we perform post reset processing we want to see if + * the bus shows 0xFF because the odd clown forgets the D7 + * pulldown resistor. + */ + if (scc_check_status(ap) == 0xFF) + return 0; + + scc_bus_post_reset(ap, devmask); + + return 0; +} + +/** + * scc_std_softreset - reset host port via ATA SRST + * @ap: port to reset + * @classes: resulting classes of attached devices + * + * Note: Original code is ata_std_softreset(). + */ + +static int scc_std_softreset (struct ata_port *ap, unsigned int *classes) +{ + unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS; + unsigned int devmask = 0, err_mask; + u8 err; + + DPRINTK("ENTER\n"); + + if (ata_port_offline(ap)) { + classes[0] = ATA_DEV_NONE; + goto out; + } + + /* determine if device 0/1 are present */ + if (scc_devchk(ap, 0)) + devmask |= (1 << 0); + if (slave_possible && scc_devchk(ap, 1)) + devmask |= (1 << 1); + + /* select device 0 again */ + ap->ops->dev_select(ap, 0); + + /* issue bus reset */ + DPRINTK("about to softreset, devmask=%x\n", devmask); + err_mask = scc_bus_softreset(ap, devmask); + if (err_mask) { + ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n", + err_mask); + return -EIO; + } + + /* determine by signature whether we have ATA or ATAPI devices */ + classes[0] = ata_dev_try_classify(ap, 0, &err); + if (slave_possible && err != 0x81) + classes[1] = ata_dev_try_classify(ap, 1, &err); + + out: + DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); + return 0; +} + +/** + * scc_bmdma_stop - Stop PCI IDE BMDMA transfer + * @qc: Command we are ending DMA for + */ + +static void scc_bmdma_stop (struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR]; + void __iomem *bmid_base = ap->host->iomap[SCC_BMID_BAR]; + u32 reg; + + while (1) { + reg = in_be32(bmid_base + SCC_DMA_INTST); + + if (reg & INTSTS_SERROR) { + printk(KERN_WARNING "%s: SERROR\n", DRV_NAME); + out_be32(bmid_base + SCC_DMA_INTST, INTSTS_SERROR|INTSTS_BMSINT); + out_be32(bmid_base + SCC_DMA_CMD, + in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); + continue; + } + + if (reg & INTSTS_PRERR) { + u32 maea0, maec0; + maea0 = in_be32(ctrl_base + SCC_CTL_MAEA0); + maec0 = in_be32(ctrl_base + SCC_CTL_MAEC0); + printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", DRV_NAME, maea0, maec0); + out_be32(bmid_base + SCC_DMA_INTST, INTSTS_PRERR|INTSTS_BMSINT); + out_be32(bmid_base + SCC_DMA_CMD, + in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); + continue; + } + + if (reg & INTSTS_RERR) { + printk(KERN_WARNING "%s: Response Error\n", DRV_NAME); + out_be32(bmid_base + SCC_DMA_INTST, INTSTS_RERR|INTSTS_BMSINT); + out_be32(bmid_base + SCC_DMA_CMD, + in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); + continue; + } + + if (reg & INTSTS_ICERR) { + out_be32(bmid_base + SCC_DMA_CMD, + in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); + printk(KERN_WARNING "%s: Illegal Configuration\n", DRV_NAME); + out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ICERR|INTSTS_BMSINT); + continue; + } + + if (reg & INTSTS_BMSINT) { + unsigned int classes; + printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME); + out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT); + /* TBD: SW reset */ + scc_std_softreset(ap, &classes); + continue; + } + + if (reg & INTSTS_BMHE) { + out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMHE); + continue; + } + + if (reg & INTSTS_ACTEINT) { + out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ACTEINT); + continue; + } + + if (reg & INTSTS_IOIRQS) { + out_be32(bmid_base + SCC_DMA_INTST, INTSTS_IOIRQS); + continue; + } + break; + } + + /* clear start/stop bit */ + out_be32(bmid_base + SCC_DMA_CMD, + in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START); + + /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ + ata_altstatus(ap); /* dummy read */ +} + +/** + * scc_bmdma_status - Read PCI IDE BMDMA status + * @ap: Port associated with this ATA transaction. + */ + +static u8 scc_bmdma_status (struct ata_port *ap) +{ + u8 host_stat; + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + host_stat = in_be32(mmio + SCC_DMA_STATUS); + + /* Workaround for PTERADD: emulate DMA_INTR when + * - IDE_STATUS[ERR] = 1 + * - INT_STATUS[INTRQ] = 1 + * - DMA_STATUS[IORACTA] = 1 + */ + if (!(host_stat & ATA_DMA_INTR)) { + u32 int_status = in_be32(mmio + SCC_DMA_INTST); + if (ata_altstatus(ap) & ATA_ERR && + int_status & INTSTS_INTRQ && + host_stat & ATA_DMA_ACTIVE) + host_stat |= ATA_DMA_INTR; + } + + return host_stat; +} + +/** + * scc_data_xfer - Transfer data by PIO + * @adev: device for this I/O + * @buf: data buffer + * @buflen: buffer length + * @write_data: read/write + * + * Note: Original code is ata_data_xfer(). + */ + +static void scc_data_xfer (struct ata_device *adev, unsigned char *buf, + unsigned int buflen, int write_data) +{ + struct ata_port *ap = adev->ap; + unsigned int words = buflen >> 1; + unsigned int i; + u16 *buf16 = (u16 *) buf; + void __iomem *mmio = ap->ioaddr.data_addr; + + /* Transfer multiple of 2 bytes */ + if (write_data) { + for (i = 0; i < words; i++) + out_be32(mmio, cpu_to_le16(buf16[i])); + } else { + for (i = 0; i < words; i++) + buf16[i] = le16_to_cpu(in_be32(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); + out_be32(mmio, cpu_to_le16(align_buf[0])); + } else { + align_buf[0] = le16_to_cpu(in_be32(mmio)); + memcpy(trailing_buf, align_buf, 1); + } + } +} + +/** + * scc_irq_on - Enable interrupts on a port. + * @ap: Port on which interrupts are enabled. + * + * Note: Original code is ata_irq_on(). + */ + +static u8 scc_irq_on (struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u8 tmp; + + ap->ctl &= ~ATA_NIEN; + ap->last_ctl = ap->ctl; + + out_be32(ioaddr->ctl_addr, ap->ctl); + tmp = ata_wait_idle(ap); + + ap->ops->irq_clear(ap); + + return tmp; +} + +/** + * scc_irq_ack - Acknowledge a device interrupt. + * @ap: Port on which interrupts are enabled. + * + * Note: Original code is ata_irq_ack(). + */ + +static u8 scc_irq_ack (struct ata_port *ap, unsigned int chk_drq) +{ + unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY; + u8 host_stat, post_stat, status; + + status = ata_busy_wait(ap, bits, 1000); + if (status & bits) + if (ata_msg_err(ap)) + printk(KERN_ERR "abnormal status 0x%X\n", status); + + /* get controller status; clear intr, err bits */ + host_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS); + out_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS, + host_stat | ATA_DMA_INTR | ATA_DMA_ERR); + + post_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS); + + if (ata_msg_intr(ap)) + printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n", + __FUNCTION__, + host_stat, post_stat, status); + + return status; +} + +/** + * scc_bmdma_freeze - Freeze BMDMA controller port + * @ap: port to freeze + * + * Note: Original code is ata_bmdma_freeze(). + */ + +static void scc_bmdma_freeze (struct ata_port *ap) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + + ap->ctl |= ATA_NIEN; + ap->last_ctl = ap->ctl; + + out_be32(ioaddr->ctl_addr, ap->ctl); + + /* Under certain circumstances, some controllers raise IRQ on + * ATA_NIEN manipulation. Also, many controllers fail to mask + * previously pending IRQ on ATA_NIEN assertion. Clear it. + */ + ata_chk_status(ap); + + ap->ops->irq_clear(ap); +} + +/** + * scc_pata_prereset - prepare for reset + * @ap: ATA port to be reset + */ + +static int scc_pata_prereset (struct ata_port *ap) +{ + ap->cbl = ATA_CBL_PATA80; + return ata_std_prereset(ap); +} + +/** + * scc_std_postreset - standard postreset callback + * @ap: the target ata_port + * @classes: classes of attached devices + * + * Note: Original code is ata_std_postreset(). + */ + +static void scc_std_postreset (struct ata_port *ap, unsigned int *classes) +{ + DPRINTK("ENTER\n"); + + /* re-enable interrupts */ + if (!ap->ops->error_handler) + ap->ops->irq_on(ap); + + /* is double-select really necessary? */ + if (classes[0] != ATA_DEV_NONE) + ap->ops->dev_select(ap, 1); + if (classes[1] != ATA_DEV_NONE) + ap->ops->dev_select(ap, 0); + + /* bail out if no device is present */ + if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) { + DPRINTK("EXIT, no device\n"); + return; + } + + /* set up device control */ + if (ap->ioaddr.ctl_addr) + out_be32(ap->ioaddr.ctl_addr, ap->ctl); + + DPRINTK("EXIT\n"); +} + +/** + * scc_error_handler - Stock error handler for BMDMA controller + * @ap: port to handle error for + */ + +static void scc_error_handler (struct ata_port *ap) +{ + ata_bmdma_drive_eh(ap, scc_pata_prereset, scc_std_softreset, NULL, + scc_std_postreset); +} + +/** + * scc_bmdma_irq_clear - Clear PCI IDE BMDMA interrupt. + * @ap: Port associated with this ATA transaction. + * + * Note: Original code is ata_bmdma_irq_clear(). + */ + +static void scc_bmdma_irq_clear (struct ata_port *ap) +{ + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + if (!mmio) + return; + + out_be32(mmio + SCC_DMA_STATUS, in_be32(mmio + SCC_DMA_STATUS)); +} + +/** + * scc_port_start - Set port up for dma. + * @ap: Port to initialize + * + * Allocate space for PRD table using ata_port_start(). + * Set PRD table address for PTERADD. (PRD Transfer End Read) + */ + +static int scc_port_start (struct ata_port *ap) +{ + void __iomem *mmio = ap->ioaddr.bmdma_addr; + int rc; + + rc = ata_port_start(ap); + if (rc) + return rc; + + out_be32(mmio + SCC_DMA_PTERADD, ap->prd_dma); + return 0; +} + +/** + * scc_port_stop - Undo scc_port_start() + * @ap: Port to shut down + * + * Reset PTERADD. + */ + +static void scc_port_stop (struct ata_port *ap) +{ + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + out_be32(mmio + SCC_DMA_PTERADD, 0); +} + +static struct scsi_host_template scc_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .ioctl = ata_scsi_ioctl, + .queuecommand = ata_scsi_queuecmd, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .slave_destroy = ata_scsi_slave_destroy, + .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, +#endif +}; + +static const struct ata_port_operations scc_pata_ops = { + .port_disable = ata_port_disable, + .set_piomode = scc_set_piomode, + .set_dmamode = scc_set_dmamode, + .mode_filter = ata_pci_default_filter, + + .tf_load = scc_tf_load, + .tf_read = scc_tf_read, + .exec_command = scc_exec_command, + .check_status = scc_check_status, + .check_altstatus = scc_check_altstatus, + .dev_select = scc_std_dev_select, + + .bmdma_setup = scc_bmdma_setup, + .bmdma_start = scc_bmdma_start, + .bmdma_stop = scc_bmdma_stop, + .bmdma_status = scc_bmdma_status, + .data_xfer = scc_data_xfer, + + .qc_prep = ata_qc_prep, + .qc_issue = ata_qc_issue_prot, + + .freeze = scc_bmdma_freeze, + .error_handler = scc_error_handler, + .post_internal_cmd = scc_bmdma_stop, + + .irq_handler = ata_interrupt, + .irq_clear = scc_bmdma_irq_clear, + .irq_on = scc_irq_on, + .irq_ack = scc_irq_ack, + + .port_start = scc_port_start, + .port_stop = scc_port_stop, +}; + +static struct ata_port_info scc_port_info[] = { + { + .sht = &scc_sht, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x00, + .udma_mask = ATA_UDMA6, + .port_ops = &scc_pata_ops, + }, +}; + +/** + * scc_reset_controller - initialize SCC PATA controller. + */ + +static int scc_reset_controller(struct ata_probe_ent *probe_ent) +{ + void __iomem *ctrl_base = probe_ent->iomap[SCC_CTRL_BAR]; + void __iomem *bmid_base = probe_ent->iomap[SCC_BMID_BAR]; + void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL; + void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG; + void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE; + void __iomem *intmask_port = bmid_base + SCC_DMA_INTMASK; + void __iomem *dmastatus_port = bmid_base + SCC_DMA_STATUS; + u32 reg = 0; + + out_be32(cckctrl_port, reg); + reg |= CCKCTRL_ATACLKOEN; + out_be32(cckctrl_port, reg); + reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN; + out_be32(cckctrl_port, reg); + reg |= CCKCTRL_CRST; + out_be32(cckctrl_port, reg); + + for (;;) { + reg = in_be32(cckctrl_port); + if (reg & CCKCTRL_CRST) + break; + udelay(5000); + } + + reg |= CCKCTRL_ATARESET; + out_be32(cckctrl_port, reg); + out_be32(ecmode_port, ECMODE_VALUE); + out_be32(mode_port, MODE_JCUSFEN); + out_be32(intmask_port, INTMASK_MSK); + + if (in_be32(dmastatus_port) & QCHSD_STPDIAG) { + printk(KERN_WARNING "%s: failed to detect 80c cable. (PDIAG# is high)\n", DRV_NAME); + return -EIO; + } + + return 0; +} + +/** + * scc_setup_ports - initialize ioaddr with SCC PATA port offsets. + * @ioaddr: IO address structure to be initialized + * @base: base address of BMID region + */ + +static void scc_setup_ports (struct ata_ioports *ioaddr, void __iomem *base) +{ + ioaddr->cmd_addr = base + SCC_REG_CMD_ADDR; + ioaddr->altstatus_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS; + ioaddr->ctl_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS; + ioaddr->bmdma_addr = base; + ioaddr->data_addr = ioaddr->cmd_addr + SCC_REG_DATA; + ioaddr->error_addr = ioaddr->cmd_addr + SCC_REG_ERR; + ioaddr->feature_addr = ioaddr->cmd_addr + SCC_REG_FEATURE; + ioaddr->nsect_addr = ioaddr->cmd_addr + SCC_REG_NSECT; + ioaddr->lbal_addr = ioaddr->cmd_addr + SCC_REG_LBAL; + ioaddr->lbam_addr = ioaddr->cmd_addr + SCC_REG_LBAM; + ioaddr->lbah_addr = ioaddr->cmd_addr + SCC_REG_LBAH; + ioaddr->device_addr = ioaddr->cmd_addr + SCC_REG_DEVICE; + ioaddr->status_addr = ioaddr->cmd_addr + SCC_REG_STATUS; + ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD; +} + +static int scc_host_init(struct ata_probe_ent *probe_ent) +{ + struct pci_dev *pdev = to_pci_dev(probe_ent->dev); + int rc; + + rc = scc_reset_controller(probe_ent); + if (rc) + return rc; + + probe_ent->n_ports = 1; + + rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + return rc; + + scc_setup_ports(&probe_ent->port[0], probe_ent->iomap[SCC_BMID_BAR]); + + pci_set_master(pdev); + + return 0; +} + +/** + * scc_init_one - Register SCC PATA device with kernel services + * @pdev: PCI device to register + * @ent: Entry in scc_pci_tbl matching with @pdev + * + * LOCKING: + * Inherited from PCI layer (may sleep). + * + * RETURNS: + * Zero on success, or -ERRNO value. + */ + +static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + unsigned int board_idx = (unsigned int) ent->driver_data; + struct device *dev = &pdev->dev; + struct ata_probe_ent *probe_ent; + int rc; + + if (!printed_version++) + dev_printk(KERN_DEBUG, &pdev->dev, + "version " DRV_VERSION "\n"); + + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + rc = pcim_iomap_regions(pdev, (1 << SCC_CTRL_BAR) | (1 << SCC_BMID_BAR), DRV_NAME); + if (rc == -EBUSY) + pcim_pin_device(pdev); + if (rc) + return rc; + + probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL); + if (!probe_ent) + return -ENOMEM; + + probe_ent->dev = dev; + INIT_LIST_HEAD(&probe_ent->node); + + probe_ent->sht = scc_port_info[board_idx].sht; + probe_ent->port_flags = scc_port_info[board_idx].flags; + probe_ent->pio_mask = scc_port_info[board_idx].pio_mask; + probe_ent->udma_mask = scc_port_info[board_idx].udma_mask; + probe_ent->port_ops = scc_port_info[board_idx].port_ops; + + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = IRQF_SHARED; + probe_ent->iomap = pcim_iomap_table(pdev); + + rc = scc_host_init(probe_ent); + if (rc) + return rc; + + if (!ata_device_add(probe_ent)) + return -ENODEV; + + devm_kfree(dev, probe_ent); + return 0; +} + +static struct pci_driver scc_pci_driver = { + .name = DRV_NAME, + .id_table = scc_pci_tbl, + .probe = scc_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +#endif +}; + +static int __init scc_init (void) +{ + int rc; + + DPRINTK("pci_register_driver\n"); + rc = pci_register_driver(&scc_pci_driver); + if (rc) + return rc; + + DPRINTK("done\n"); + return 0; +} + +static void __exit scc_exit (void) +{ + pci_unregister_driver(&scc_pci_driver); +} + +module_init(scc_init); +module_exit(scc_exit); + +MODULE_AUTHOR("Toshiba corp"); +MODULE_DESCRIPTION("SCSI low-level driver for Toshiba SCC PATA controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, scc_pci_tbl); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c index ad5b43fef3d..598eef810a7 100644 --- a/drivers/ata/pata_serverworks.c +++ b/drivers/ata/pata_serverworks.c @@ -41,7 +41,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_serverworks" -#define DRV_VERSION "0.3.9" +#define DRV_VERSION "0.4.0" #define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ #define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ @@ -319,8 +319,10 @@ static struct scsi_host_template serverworks_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations serverworks_osb4_port_ops = { @@ -548,6 +550,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id return ata_pci_init_one(pdev, port_info, ports); } +#ifdef CONFIG_PM static int serverworks_reinit_one(struct pci_dev *pdev) { /* Force master latency timer to 64 PCI clocks */ @@ -571,6 +574,7 @@ static int serverworks_reinit_one(struct pci_dev *pdev) } return ata_pci_device_resume(pdev); } +#endif static const struct pci_device_id serverworks[] = { { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0}, @@ -587,8 +591,10 @@ static struct pci_driver serverworks_pci_driver = { .id_table = serverworks, .probe = serverworks_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = serverworks_reinit_one, +#endif }; static int __init serverworks_init(void) diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index ed79fabe025..dab2889a556 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -33,7 +33,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_sil680" -#define DRV_VERSION "0.4.1" +#define DRV_VERSION "0.4.5" /** * sil680_selreg - return register base @@ -139,10 +139,13 @@ static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev) unsigned long tfaddr = sil680_selreg(ap, 0x02); unsigned long addr = sil680_seldev(ap, adev, 0x04); + unsigned long addr_mask = 0x80 + 4 * ap->port_no; struct pci_dev *pdev = to_pci_dev(ap->host->dev); int pio = adev->pio_mode - XFER_PIO_0; int lowest_pio = pio; + int port_shift = 4 * adev->devno; u16 reg; + u8 mode; struct ata_device *pair = ata_dev_pair(adev); @@ -153,10 +156,17 @@ static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev) pci_write_config_word(pdev, tfaddr, speed_t[lowest_pio]); pci_read_config_word(pdev, tfaddr-2, ®); + pci_read_config_byte(pdev, addr_mask, &mode); + reg &= ~0x0200; /* Clear IORDY */ - if (ata_pio_need_iordy(adev)) + mode &= ~(3 << port_shift); /* Clear IORDY and DMA bits */ + + if (ata_pio_need_iordy(adev)) { reg |= 0x0200; /* Enable IORDY */ + mode |= 1 << port_shift; + } pci_write_config_word(pdev, tfaddr-2, reg); + pci_write_config_byte(pdev, addr_mask, mode); } /** @@ -226,6 +236,10 @@ static struct scsi_host_template sil680_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM + .suspend = ata_scsi_device_suspend, + .resume = ata_scsi_device_resume, +#endif }; static struct ata_port_operations sil680_port_ops = { @@ -367,11 +381,13 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +#ifdef CONFIG_PM static int sil680_reinit_one(struct pci_dev *pdev) { sil680_init_chip(pdev); return ata_pci_device_resume(pdev); } +#endif static const struct pci_device_id sil680[] = { { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), }, @@ -384,8 +400,10 @@ static struct pci_driver sil680_pci_driver = { .id_table = sil680, .probe = sil680_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = sil680_reinit_one, +#endif }; static int __init sil680_init(void) diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c index 560103d55b2..f4820786593 100644 --- a/drivers/ata/pata_sis.c +++ b/drivers/ata/pata_sis.c @@ -32,11 +32,10 @@ #include <scsi/scsi_host.h> #include <linux/libata.h> #include <linux/ata.h> -#include "libata.h" +#include "sis.h" -#undef DRV_NAME /* already defined in libata.h, for libata-core */ #define DRV_NAME "pata_sis" -#define DRV_VERSION "0.4.5" +#define DRV_VERSION "0.5.0" struct sis_chipset { u16 device; /* PCI host ID */ @@ -151,7 +150,7 @@ static int sis_66_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) { ata_port_disable(ap); - printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); + ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n"); return 0; } /* Older chips keep cable detect in bits 4/5 of reg 0x48 */ @@ -197,7 +196,7 @@ static int sis_old_pre_reset(struct ata_port *ap) if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) { ata_port_disable(ap); - printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id); + ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n"); return 0; } ap->cbl = ATA_CBL_PATA40; @@ -576,8 +575,10 @@ static struct scsi_host_template sis_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static const struct ata_port_operations sis_133_ops = { @@ -1033,8 +1034,10 @@ static struct pci_driver sis_pci_driver = { .id_table = sis_pci_tbl, .probe = sis_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init sis_init(void) diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index 96e890fd645..b681441cfcb 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -7,6 +7,13 @@ * SL82C105/Winbond 553 IDE driver * * and in part on the documentation and errata sheet + * + * + * Note: The controller like many controllers has shared timings for + * PIO and DMA. We thus flip to the DMA timings in dma_start and flip back + * in the dma_stop function. Thus we actually don't need a set_dmamode + * method as the PIO method is always called and will set the right PIO + * timing parameters. */ #include <linux/kernel.h> @@ -19,7 +26,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_sl82c105" -#define DRV_VERSION "0.2.3" +#define DRV_VERSION "0.3.0" enum { /* @@ -126,33 +133,6 @@ static void sl82c105_configure_dmamode(struct ata_port *ap, struct ata_device *a } /** - * sl82c105_set_dmamode - set initial DMA mode data - * @ap: ATA interface - * @adev: ATA device - * - * Called to do the DMA mode setup. This replaces the PIO timings - * for the device in question. Set appropriate PIO timings not DMA - * timings at this point. - */ - -static void sl82c105_set_dmamode(struct ata_port *ap, struct ata_device *adev) -{ - switch(adev->dma_mode) { - case XFER_MW_DMA_0: - sl82c105_configure_piomode(ap, adev, 0); - break; - case XFER_MW_DMA_1: - sl82c105_configure_piomode(ap, adev, 3); - break; - case XFER_MW_DMA_2: - sl82c105_configure_piomode(ap, adev, 4); - break; - default: - BUG(); - } -} - -/** * sl82c105_reset_engine - Reset the DMA engine * @ap: ATA interface * @@ -222,7 +202,7 @@ static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc) /* This will redo the initial setup of the DMA device to matching PIO timings */ - sl82c105_set_dmamode(ap, qc->dev); + sl82c105_set_piomode(ap, qc->dev); } static struct scsi_host_template sl82c105_sht = { @@ -246,7 +226,6 @@ static struct scsi_host_template sl82c105_sht = { static struct ata_port_operations sl82c105_port_ops = { .port_disable = ata_port_disable, .set_piomode = sl82c105_set_piomode, - .set_dmamode = sl82c105_set_dmamode, .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, @@ -255,7 +234,10 @@ static struct ata_port_operations sl82c105_port_ops = { .exec_command = ata_exec_command, .dev_select = ata_std_dev_select, + .freeze = ata_bmdma_freeze, + .thaw = ata_bmdma_thaw, .error_handler = sl82c105_error_handler, + .post_internal_cmd = ata_bmdma_post_internal_cmd, .bmdma_setup = ata_bmdma_setup, .bmdma_start = sl82c105_bmdma_start, diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c index 453ab90b721..71418f2a0cd 100644 --- a/drivers/ata/pata_triflex.c +++ b/drivers/ata/pata_triflex.c @@ -193,8 +193,10 @@ static struct scsi_host_template triflex_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations triflex_port_ops = { @@ -260,8 +262,10 @@ static struct pci_driver triflex_pci_driver = { .id_table = triflex, .probe = triflex_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = ata_pci_device_resume, +#endif }; static int __init triflex_init(void) diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 220fcd6c549..946ade0e1f1 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -170,7 +170,7 @@ static int via_pre_reset(struct ata_port *ap) ap->cbl = ATA_CBL_PATA40; else ap->cbl = ATA_CBL_PATA_UNK; - + return ata_std_prereset(ap); } @@ -305,8 +305,10 @@ static struct scsi_host_template via_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .resume = ata_scsi_device_resume, .suspend = ata_scsi_device_suspend, +#endif }; static struct ata_port_operations via_port_ops = { @@ -560,6 +562,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return ata_pci_init_one(pdev, port_info, 2); } +#ifdef CONFIG_PM /** * via_reinit_one - reinit after resume * @pdev; PCI device @@ -592,6 +595,7 @@ static int via_reinit_one(struct pci_dev *pdev) } return ata_pci_device_resume(pdev); } +#endif static const struct pci_device_id via[] = { { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), }, @@ -607,8 +611,10 @@ static struct pci_driver via_pci_driver = { .id_table = via, .probe = via_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = via_reinit_one, +#endif }; static int __init via_init(void) diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c index 0888b4f19f4..6c111035fc8 100644 --- a/drivers/ata/pata_winbond.c +++ b/drivers/ata/pata_winbond.c @@ -17,7 +17,7 @@ #include <linux/platform_device.h> #define DRV_NAME "pata_winbond" -#define DRV_VERSION "0.0.1" +#define DRV_VERSION "0.0.2" #define NR_HOST 4 /* Two winbond controllers, two channels each */ diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c index 857ac23217a..5dd3ca8b5f2 100644 --- a/drivers/ata/pdc_adma.c +++ b/drivers/ata/pdc_adma.c @@ -44,7 +44,7 @@ #include <linux/libata.h> #define DRV_NAME "pdc_adma" -#define DRV_VERSION "0.04" +#define DRV_VERSION "0.05" /* macro to calculate base address for ATA regs */ #define ADMA_ATA_REGS(base,port_no) ((base) + ((port_no) * 0x40)) @@ -498,7 +498,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host) if ((status & ATA_BUSY)) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", - ap->id, qc->tf.protocol, status); + ap->print_id, qc->tf.protocol, status); /* complete taskfile transaction */ pp->state = adma_state_idle; diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c index 31b636fac98..3193a603d1a 100644 --- a/drivers/ata/sata_inic162x.c +++ b/drivers/ata/sata_inic162x.c @@ -135,8 +135,10 @@ static struct scsi_host_template inic_sht = { .slave_configure = inic_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .suspend = ata_scsi_device_suspend, .resume = ata_scsi_device_resume, +#endif }; static const int scr_map[] = { @@ -632,6 +634,7 @@ static int init_controller(void __iomem *mmio_base, u16 hctl) return 0; } +#ifdef CONFIG_PM static int inic_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); @@ -642,7 +645,6 @@ static int inic_pci_device_resume(struct pci_dev *pdev) ata_pci_device_do_resume(pdev); if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { - printk("XXX\n"); rc = init_controller(mmio_base, hpriv->cached_hctl); if (rc) return rc; @@ -652,6 +654,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev) return 0; } +#endif static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -755,8 +758,10 @@ static const struct pci_device_id inic_pci_tbl[] = { static struct pci_driver inic_pci_driver = { .name = DRV_NAME, .id_table = inic_pci_tbl, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = inic_pci_device_resume, +#endif .probe = inic_init_one, .remove = ata_pci_remove_one, }; diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index d689df52eae..a65ba636aaa 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -35,7 +35,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_mv" -#define DRV_VERSION "0.7" +#define DRV_VERSION "0.8" enum { /* BAR's are enumerated in terms of pci_resource_start() terms */ @@ -137,14 +137,19 @@ enum { PCI_ERR = (1 << 18), TRAN_LO_DONE = (1 << 19), /* 6xxx: IRQ coalescing */ TRAN_HI_DONE = (1 << 20), /* 6xxx: IRQ coalescing */ + PORTS_0_3_COAL_DONE = (1 << 8), + PORTS_4_7_COAL_DONE = (1 << 17), PORTS_0_7_COAL_DONE = (1 << 21), /* 6xxx: IRQ coalescing */ GPIO_INT = (1 << 22), SELF_INT = (1 << 23), TWSI_INT = (1 << 24), HC_MAIN_RSVD = (0x7f << 25), /* bits 31-25 */ + HC_MAIN_RSVD_5 = (0x1fff << 19), /* bits 31-19 */ HC_MAIN_MASKED_IRQS = (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE | GPIO_INT | TWSI_INT | HC_MAIN_RSVD), + HC_MAIN_MASKED_IRQS_5 = (PORTS_0_3_COAL_DONE | PORTS_4_7_COAL_DONE | + HC_MAIN_RSVD_5), /* SATAHC registers */ HC_CFG_OFS = 0, @@ -814,23 +819,27 @@ static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio) u32 cfg = readl(port_mmio + EDMA_CFG_OFS); /* set up non-NCQ EDMA configuration */ - cfg &= ~0x1f; /* clear queue depth */ - cfg &= ~EDMA_CFG_NCQ; /* clear NCQ mode */ cfg &= ~(1 << 9); /* disable equeue */ - if (IS_GEN_I(hpriv)) + if (IS_GEN_I(hpriv)) { + cfg &= ~0x1f; /* clear queue depth */ cfg |= (1 << 8); /* enab config burst size mask */ + } - else if (IS_GEN_II(hpriv)) + else if (IS_GEN_II(hpriv)) { + cfg &= ~0x1f; /* clear queue depth */ cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN; + cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */ + } else if (IS_GEN_IIE(hpriv)) { - cfg |= (1 << 23); /* dis RX PM port mask */ - cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */ + cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */ + cfg |= (1 << 22); /* enab 4-entry host queue cache */ cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */ cfg |= (1 << 18); /* enab early completion */ - cfg |= (1 << 17); /* enab host q cache */ - cfg |= (1 << 22); /* enab cutthrough */ + cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */ + cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */ + cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */ } writelfl(cfg, port_mmio + EDMA_CFG_OFS); @@ -1276,7 +1285,7 @@ static void mv_err_intr(struct ata_port *ap, int reset_allowed) pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; } DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x " - "SERR: 0x%08x\n", ap->id, edma_err_cause, serr); + "SERR: 0x%08x\n", ap->print_id, edma_err_cause, serr); /* Clear EDMA now that SERR cleanup done */ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); @@ -2052,7 +2061,7 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio) port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS; /* unused: */ - port->cmd_addr = port->bmdma_addr = port->scr_addr = 0; + port->cmd_addr = port->bmdma_addr = port->scr_addr = NULL; /* Clear any currently outstanding port interrupt conditions */ serr_ofs = mv_scr_offset(SCR_ERROR); @@ -2240,7 +2249,11 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent, /* and unmask interrupt generation for host regs */ writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS); - writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); + + if (IS_50XX(hpriv)) + writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS); + else + writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " "PCI int cause/mask=0x%08x/0x%08x\n", @@ -2347,7 +2360,7 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; /* Enable interrupts */ - if (msi && !pci_enable_msi(pdev)) + if (msi && pci_enable_msi(pdev)) pci_intx(pdev, 1); mv_dump_pci_cfg(pdev, 0x68); diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index ab92f208dae..9d9670a9b11 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -219,6 +219,7 @@ struct nv_adma_port_priv { void __iomem * gen_block; void __iomem * notifier_clear_block; u8 flags; + int last_issue_ncq; }; struct nv_host_priv { @@ -229,7 +230,9 @@ struct nv_host_priv { static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void nv_remove_one (struct pci_dev *pdev); +#ifdef CONFIG_PM static int nv_pci_device_resume(struct pci_dev *pdev); +#endif static void nv_ck804_host_stop(struct ata_host *host); static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance); @@ -250,14 +253,13 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance); static void nv_adma_irq_clear(struct ata_port *ap); static int nv_adma_port_start(struct ata_port *ap); static void nv_adma_port_stop(struct ata_port *ap); +#ifdef CONFIG_PM static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg); static int nv_adma_port_resume(struct ata_port *ap); +#endif static void nv_adma_error_handler(struct ata_port *ap); static void nv_adma_host_stop(struct ata_host *host); -static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc); -static void nv_adma_bmdma_start(struct ata_queued_cmd *qc); -static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc); -static u8 nv_adma_bmdma_status(struct ata_port *ap); +static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc); enum nv_host_type { @@ -297,8 +299,10 @@ static struct pci_driver nv_pci_driver = { .name = DRV_NAME, .id_table = nv_pci_tbl, .probe = nv_init_one, +#ifdef CONFIG_PM .suspend = ata_pci_device_suspend, .resume = nv_pci_device_resume, +#endif .remove = nv_remove_one, }; @@ -318,8 +322,10 @@ static struct scsi_host_template nv_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .suspend = ata_scsi_device_suspend, .resume = ata_scsi_device_resume, +#endif }; static struct scsi_host_template nv_adma_sht = { @@ -338,8 +344,10 @@ static struct scsi_host_template nv_adma_sht = { .slave_configure = nv_adma_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .suspend = ata_scsi_device_suspend, .resume = ata_scsi_device_resume, +#endif }; static const struct ata_port_operations nv_generic_ops = { @@ -432,16 +440,16 @@ static const struct ata_port_operations nv_adma_ops = { .exec_command = ata_exec_command, .check_status = ata_check_status, .dev_select = ata_std_dev_select, - .bmdma_setup = nv_adma_bmdma_setup, - .bmdma_start = nv_adma_bmdma_start, - .bmdma_stop = nv_adma_bmdma_stop, - .bmdma_status = nv_adma_bmdma_status, + .bmdma_setup = ata_bmdma_setup, + .bmdma_start = ata_bmdma_start, + .bmdma_stop = ata_bmdma_stop, + .bmdma_status = ata_bmdma_status, .qc_prep = nv_adma_qc_prep, .qc_issue = nv_adma_qc_issue, .freeze = nv_ck804_freeze, .thaw = nv_ck804_thaw, .error_handler = nv_adma_error_handler, - .post_internal_cmd = nv_adma_bmdma_stop, + .post_internal_cmd = nv_adma_post_internal_cmd, .data_xfer = ata_data_xfer, .irq_handler = nv_adma_interrupt, .irq_clear = nv_adma_irq_clear, @@ -451,8 +459,10 @@ static const struct ata_port_operations nv_adma_ops = { .scr_write = nv_scr_write, .port_start = nv_adma_port_start, .port_stop = nv_adma_port_stop, +#ifdef CONFIG_PM .port_suspend = nv_adma_port_suspend, .port_resume = nv_adma_port_resume, +#endif .host_stop = nv_adma_host_stop, }; @@ -661,30 +671,31 @@ static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb) { unsigned int idx = 0; - cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device | WNB); - - if ((tf->flags & ATA_TFLAG_LBA48) == 0) { - cpb[idx++] = cpu_to_le16(IGN); - cpb[idx++] = cpu_to_le16(IGN); - cpb[idx++] = cpu_to_le16(IGN); - cpb[idx++] = cpu_to_le16(IGN); - cpb[idx++] = cpu_to_le16(IGN); - } - else { - cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->hob_feature); - cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect); - cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->hob_lbal); - cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->hob_lbam); - cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->hob_lbah); + if(tf->flags & ATA_TFLAG_ISADDR) { + if (tf->flags & ATA_TFLAG_LBA48) { + cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->hob_feature | WNB); + cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->hob_nsect); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->hob_lbal); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->hob_lbam); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->hob_lbah); + cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature); + } else + cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature | WNB); + + cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->nsect); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->lbal); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->lbam); + cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->lbah); } - cpb[idx++] = cpu_to_le16((ATA_REG_ERR << 8) | tf->feature); - cpb[idx++] = cpu_to_le16((ATA_REG_NSECT << 8) | tf->nsect); - cpb[idx++] = cpu_to_le16((ATA_REG_LBAL << 8) | tf->lbal); - cpb[idx++] = cpu_to_le16((ATA_REG_LBAM << 8) | tf->lbam); - cpb[idx++] = cpu_to_le16((ATA_REG_LBAH << 8) | tf->lbah); + + if(tf->flags & ATA_TFLAG_DEVICE) + cpb[idx++] = cpu_to_le16((ATA_REG_DEVICE << 8) | tf->device); cpb[idx++] = cpu_to_le16((ATA_REG_CMD << 8) | tf->command | CMDEND); + while(idx < 12) + cpb[idx++] = cpu_to_le16(IGN); + return idx; } @@ -741,6 +752,17 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num, qc->err_mask); ata_qc_complete(qc); + } else { + struct ata_eh_info *ehi = &ap->eh_info; + /* Notifier bits set without a command may indicate the drive + is misbehaving. Raise host state machine violation on this + condition. */ + ata_port_printk(ap, KERN_ERR, "notifier for tag %d with no command?\n", + cpb_num); + ehi->err_mask |= AC_ERR_HSM; + ehi->action |= ATA_EH_SOFTRESET; + ata_port_freeze(ap); + return 1; } } return 0; @@ -852,22 +874,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) if (status & (NV_ADMA_STAT_DONE | NV_ADMA_STAT_CPBERR)) { - /** Check CPBs for completed commands */ + u32 check_commands; + int pos, error = 0; + + if(ata_tag_valid(ap->active_tag)) + check_commands = 1 << ap->active_tag; + else + check_commands = ap->sactive; - if (ata_tag_valid(ap->active_tag)) { - /* Non-NCQ command */ - nv_adma_check_cpb(ap, ap->active_tag, - notifier_error & (1 << ap->active_tag)); - } else { - int pos, error = 0; - u32 active = ap->sactive; - - while ((pos = ffs(active)) && !error) { - pos--; - error = nv_adma_check_cpb(ap, pos, - notifier_error & (1 << pos) ); - active &= ~(1 << pos ); - } + /** Check CPBs for completed commands */ + while ((pos = ffs(check_commands)) && !error) { + pos--; + error = nv_adma_check_cpb(ap, pos, + notifier_error & (1 << pos) ); + check_commands &= ~(1 << pos ); } } } @@ -905,73 +925,12 @@ static void nv_adma_irq_clear(struct ata_port *ap) iowrite8(ioread8(dma_stat_addr), dma_stat_addr); } -static void nv_adma_bmdma_setup(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); - struct nv_adma_port_priv *pp = ap->private_data; - u8 dmactl; - - if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { - WARN_ON(1); - return; - } - - /* load PRD table addr. */ - iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); - - /* specify data direction, triple-check start bit is clear */ - dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - dmactl &= ~(ATA_DMA_WR | ATA_DMA_START); - if (!rw) - dmactl |= ATA_DMA_WR; - - iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - - /* issue r/w command */ - ata_exec_command(ap, &qc->tf); -} - -static void nv_adma_bmdma_start(struct ata_queued_cmd *qc) +static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc) { - struct ata_port *ap = qc->ap; - struct nv_adma_port_priv *pp = ap->private_data; - u8 dmactl; - - if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) { - WARN_ON(1); - return; - } - - /* start host DMA transaction */ - dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - iowrite8(dmactl | ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); -} - -static void nv_adma_bmdma_stop(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct nv_adma_port_priv *pp = ap->private_data; - - if(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)) - return; - - /* clear start/stop bit */ - iowrite8(ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START, - ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - - /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ - ata_altstatus(ap); /* dummy read */ -} - -static u8 nv_adma_bmdma_status(struct ata_port *ap) -{ - struct nv_adma_port_priv *pp = ap->private_data; - - WARN_ON(!(pp->flags & NV_ADMA_PORT_REGISTER_MODE)); + struct nv_adma_port_priv *pp = qc->ap->private_data; - return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + if(pp->flags & NV_ADMA_PORT_REGISTER_MODE) + ata_bmdma_post_internal_cmd(qc); } static int nv_adma_port_start(struct ata_port *ap) @@ -1040,14 +999,15 @@ static int nv_adma_port_start(struct ata_port *ap) /* clear GO for register mode, enable interrupt */ tmp = readw(mmio + NV_ADMA_CTL); - writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); + writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN | + NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL); tmp = readw(mmio + NV_ADMA_CTL); writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); - readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + readw( mmio + NV_ADMA_CTL ); /* flush posted write */ udelay(1); writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); - readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + readw( mmio + NV_ADMA_CTL ); /* flush posted write */ return 0; } @@ -1061,6 +1021,7 @@ static void nv_adma_port_stop(struct ata_port *ap) writew(0, mmio + NV_ADMA_CTL); } +#ifdef CONFIG_PM static int nv_adma_port_suspend(struct ata_port *ap, pm_message_t mesg) { struct nv_adma_port_priv *pp = ap->private_data; @@ -1099,17 +1060,19 @@ static int nv_adma_port_resume(struct ata_port *ap) /* clear GO for register mode, enable interrupt */ tmp = readw(mmio + NV_ADMA_CTL); - writew((tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN, mmio + NV_ADMA_CTL); + writew( (tmp & ~NV_ADMA_CTL_GO) | NV_ADMA_CTL_AIEN | + NV_ADMA_CTL_HOTPLUG_IEN, mmio + NV_ADMA_CTL); tmp = readw(mmio + NV_ADMA_CTL); writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); - readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + readw( mmio + NV_ADMA_CTL ); /* flush posted write */ udelay(1); writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); - readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + readw( mmio + NV_ADMA_CTL ); /* flush posted write */ return 0; } +#endif static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port) { @@ -1163,11 +1126,7 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, int idx, struct nv_adma_prd *aprd) { - u8 flags; - - memset(aprd, 0, sizeof(struct nv_adma_prd)); - - flags = 0; + u8 flags = 0; if (qc->tf.flags & ATA_TFLAG_WRITE) flags |= NV_APRD_WRITE; if (idx == qc->n_elem - 1) @@ -1178,6 +1137,7 @@ static void nv_adma_fill_aprd(struct ata_queued_cmd *qc, aprd->addr = cpu_to_le64(((u64)sg_dma_address(sg))); aprd->len = cpu_to_le32(((u32)sg_dma_len(sg))); /* len in bytes */ aprd->flags = flags; + aprd->packet_len = 0; } static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb) @@ -1198,6 +1158,8 @@ static void nv_adma_fill_sg(struct ata_queued_cmd *qc, struct nv_adma_cpb *cpb) } if (idx > 5) cpb->next_aprd = cpu_to_le64(((u64)(pp->aprd_dma + NV_ADMA_SGTBL_SZ * qc->tag))); + else + cpb->next_aprd = cpu_to_le64(0); } static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc) @@ -1230,7 +1192,10 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc) return; } - memset(cpb, 0, sizeof(struct nv_adma_cpb)); + cpb->resp_flags = NV_CPB_RESP_DONE; + wmb(); + cpb->ctl_flags = 0; + wmb(); cpb->len = 3; cpb->tag = qc->tag; @@ -1254,12 +1219,15 @@ static void nv_adma_qc_prep(struct ata_queued_cmd *qc) finished filling in all of the contents */ wmb(); cpb->ctl_flags = ctl_flags; + wmb(); + cpb->resp_flags = 0; } static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) { struct nv_adma_port_priv *pp = qc->ap->private_data; void __iomem *mmio = pp->ctl_block; + int curr_ncq = (qc->tf.protocol == ATA_PROT_NCQ); VPRINTK("ENTER\n"); @@ -1274,6 +1242,14 @@ static unsigned int nv_adma_qc_issue(struct ata_queued_cmd *qc) /* write append register, command tag in lower 8 bits and (number of cpbs to append -1) in top 8 bits */ wmb(); + + if(curr_ncq != pp->last_issue_ncq) { + /* Seems to need some delay before switching between NCQ and non-NCQ + commands, else we get command timeouts and such. */ + udelay(20); + pp->last_issue_ncq = curr_ncq; + } + writew(qc->tag, mmio + NV_ADMA_APPEND); DPRINTK("Issued tag %u\n",qc->tag); @@ -1447,6 +1423,30 @@ static void nv_adma_error_handler(struct ata_port *ap) int i; u16 tmp; + if(ata_tag_valid(ap->active_tag) || ap->sactive) { + u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); + u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); + u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL); + u32 status = readw(mmio + NV_ADMA_STAT); + u8 cpb_count = readb(mmio + NV_ADMA_CPB_COUNT); + u8 next_cpb_idx = readb(mmio + NV_ADMA_NEXT_CPB_IDX); + + ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X " + "notifier_error 0x%X gen_ctl 0x%X status 0x%X " + "next cpb count 0x%X next cpb idx 0x%x\n", + notifier, notifier_error, gen_ctl, status, + cpb_count, next_cpb_idx); + + for( i=0;i<NV_ADMA_MAX_CPBS;i++) { + struct nv_adma_cpb *cpb = &pp->cpb[i]; + if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) || + ap->sactive & (1 << i) ) + ata_port_printk(ap, KERN_ERR, + "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", + i, cpb->ctl_flags, cpb->resp_flags); + } + } + /* Push us back into port register mode for error handling. */ nv_adma_register_mode(ap); @@ -1460,10 +1460,10 @@ static void nv_adma_error_handler(struct ata_port *ap) /* Reset channel */ tmp = readw(mmio + NV_ADMA_CTL); writew(tmp | NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); - readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + readw( mmio + NV_ADMA_CTL ); /* flush posted write */ udelay(1); writew(tmp & ~NV_ADMA_CTL_CHANNEL_RESET, mmio + NV_ADMA_CTL); - readl( mmio + NV_ADMA_CTL ); /* flush posted write */ + readw( mmio + NV_ADMA_CTL ); /* flush posted write */ } ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, @@ -1575,6 +1575,7 @@ static void nv_remove_one (struct pci_dev *pdev) kfree(hpriv); } +#ifdef CONFIG_PM static int nv_pci_device_resume(struct pci_dev *pdev) { struct ata_host *host = dev_get_drvdata(&pdev->dev); @@ -1622,6 +1623,7 @@ static int nv_pci_device_resume(struct pci_dev *pdev) return 0; } +#endif static void nv_ck804_host_stop(struct ata_host *host) { diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index cf9ed8c3930..2339813ce9f 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -45,7 +45,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "1.05" +#define DRV_VERSION "2.00" enum { @@ -218,6 +218,7 @@ static const struct ata_port_operations pdc_pata_ops = { .freeze = pdc_freeze, .thaw = pdc_thaw, .error_handler = pdc_error_handler, + .post_internal_cmd = pdc_post_internal_cmd, .data_xfer = ata_data_xfer, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, @@ -776,7 +777,8 @@ static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc) return pdc_check_atapi_dma(qc); } -static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) +static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base, + void __iomem *scr_addr) { port->cmd_addr = base; port->data_addr = base; @@ -791,6 +793,7 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base) port->status_addr = base + 0x1c; port->altstatus_addr = port->ctl_addr = base + 0x38; + port->scr_addr = scr_addr; } @@ -903,11 +906,8 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e base = probe_ent->iomap[PDC_MMIO_BAR]; - pdc_ata_setup_port(&probe_ent->port[0], base + 0x200); - pdc_ata_setup_port(&probe_ent->port[1], base + 0x280); - - probe_ent->port[0].scr_addr = base + 0x400; - probe_ent->port[1].scr_addr = base + 0x500; + pdc_ata_setup_port(&probe_ent->port[0], base + 0x200, base + 0x400); + pdc_ata_setup_port(&probe_ent->port[1], base + 0x280, base + 0x500); /* notice 4-port boards */ switch (board_idx) { @@ -916,12 +916,8 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e /* Fall through */ case board_20319: probe_ent->n_ports = 4; - - pdc_ata_setup_port(&probe_ent->port[2], base + 0x300); - pdc_ata_setup_port(&probe_ent->port[3], base + 0x380); - - probe_ent->port[2].scr_addr = base + 0x600; - probe_ent->port[3].scr_addr = base + 0x700; + pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, base + 0x600); + pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, base + 0x700); break; case board_2057x: hp->flags |= PDC_FLAG_GEN_II; @@ -931,7 +927,7 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e tmp = readb(base + PDC_FLASH_CTL+1); if (!(tmp & 0x80)) { probe_ent->n_ports = 3; - pdc_ata_setup_port(&probe_ent->port[2], base + 0x300); + pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL); hp->port_flags[2] = ATA_FLAG_SLAVE_POSS; printk(KERN_INFO DRV_NAME " PATA port found\n"); } else @@ -941,12 +937,8 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e break; case board_20619: probe_ent->n_ports = 4; - - pdc_ata_setup_port(&probe_ent->port[2], base + 0x300); - pdc_ata_setup_port(&probe_ent->port[3], base + 0x380); - - probe_ent->port[2].scr_addr = base + 0x600; - probe_ent->port[3].scr_addr = base + 0x700; + pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL); + pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, NULL); break; default: BUG(); diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c index 6097d8f2a0c..8786b45f291 100644 --- a/drivers/ata/sata_qstor.c +++ b/drivers/ata/sata_qstor.c @@ -39,7 +39,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_qstor" -#define DRV_VERSION "0.06" +#define DRV_VERSION "0.07" enum { QS_MMIO_BAR = 4, @@ -446,7 +446,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host) if ((status & ATA_BUSY)) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", - ap->id, qc->tf.protocol, status); + ap->print_id, qc->tf.protocol, status); /* complete taskfile transaction */ pp->state = qs_state_idle; diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index dca3d3749f0..917b7ea4ef7 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -46,7 +46,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_sil" -#define DRV_VERSION "2.0" +#define DRV_VERSION "2.1" enum { SIL_MMIO_BAR = 5, @@ -183,8 +183,10 @@ static struct scsi_host_template sil_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .suspend = ata_scsi_device_suspend, .resume = ata_scsi_device_resume, +#endif }; static const struct ata_port_operations sil_ops = { @@ -339,7 +341,7 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re break; } - return 0; + return NULL; } static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) @@ -386,9 +388,15 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2) goto freeze; } - if (unlikely(!qc || qc->tf.ctl & ATA_NIEN)) + if (unlikely(!qc)) goto freeze; + if (unlikely(qc->tf.flags & ATA_TFLAG_POLLING)) { + /* this sometimes happens, just clear IRQ */ + ata_chk_status(ap); + return; + } + /* Check whether we are expecting interrupt in this state */ switch (ap->hsm_task_state) { case HSM_ST_FIRST: diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index e65e8d55da3..75d96159965 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -30,7 +30,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_sil24" -#define DRV_VERSION "0.3" +#define DRV_VERSION "0.8" /* * Port request block (PRB) 32 bytes @@ -380,8 +380,10 @@ static struct scsi_host_template sil24_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, +#ifdef CONFIG_PM .suspend = ata_scsi_device_suspend, .resume = ata_scsi_device_resume, +#endif }; static const struct ata_port_operations sil24_ops = { @@ -647,7 +649,6 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, struct sil24_sge *sge) { struct scatterlist *sg; - unsigned int idx = 0; ata_for_each_sg(sg, qc) { sge->addr = cpu_to_le64(sg_dma_address(sg)); @@ -656,9 +657,7 @@ static inline void sil24_fill_sg(struct ata_queued_cmd *qc, sge->flags = cpu_to_le32(SGE_TRM); else sge->flags = 0; - sge++; - idx++; } } diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 49c9e2bd706..1879e0cd56a 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -40,9 +40,8 @@ #include <linux/device.h> #include <scsi/scsi_host.h> #include <linux/libata.h> -#include "libata.h" +#include "sis.h" -#undef DRV_NAME /* already defined in libata.h, for libata-core */ #define DRV_NAME "sata_sis" #define DRV_VERSION "0.7" @@ -310,7 +309,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) case 0x10: ppi[1] = &sis_info133; break; - + case 0x30: ppi[0] = &sis_info133; break; diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 4e428999420..b121195cc59 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -53,7 +53,7 @@ #endif /* CONFIG_PPC_OF */ #define DRV_NAME "sata_svw" -#define DRV_VERSION "2.0" +#define DRV_VERSION "2.1" enum { K2_FLAG_NO_ATAPI_DMA = (1 << 29), diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index 0ebd77b080d..1a081c3a8c0 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c @@ -44,7 +44,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_sx4" -#define DRV_VERSION "0.9" +#define DRV_VERSION "0.10" enum { @@ -421,7 +421,7 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc) WARN_ON(!(qc->flags & ATA_QCFLAG_DMAMAP)); - VPRINTK("ata%u: ENTER\n", ap->id); + VPRINTK("ata%u: ENTER\n", ap->print_id); /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -478,7 +478,7 @@ static void pdc20621_nodata_prep(struct ata_queued_cmd *qc) unsigned int portno = ap->port_no; unsigned int i; - VPRINTK("ata%u: ENTER\n", ap->id); + VPRINTK("ata%u: ENTER\n", ap->print_id); /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -605,7 +605,7 @@ static void pdc20621_packet_start(struct ata_queued_cmd *qc) /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; - VPRINTK("ata%u: ENTER\n", ap->id); + VPRINTK("ata%u: ENTER\n", ap->print_id); wmb(); /* flush PRD, pkt writes */ @@ -672,7 +672,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, /* step two - DMA from DIMM to host */ if (doing_hdma) { - VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, + VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->print_id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* get drive status; clear intr; complete txn */ qc->err_mask |= ac_err_mask(ata_wait_idle(ap)); @@ -683,7 +683,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, /* step one - exec ATA command */ else { u8 seq = (u8) (port_no + 1 + 4); - VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id, + VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->print_id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* submit hdma pkt */ @@ -698,7 +698,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, /* step one - DMA from host to DIMM */ if (doing_hdma) { u8 seq = (u8) (port_no + 1); - VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id, + VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->print_id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* submit ata pkt */ @@ -711,7 +711,7 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap, /* step two - execute ATA command */ else { - VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, + VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->print_id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* get drive status; clear intr; complete txn */ qc->err_mask |= ac_err_mask(ata_wait_idle(ap)); diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c index 80131eec68f..d659ace80f4 100644 --- a/drivers/ata/sata_uli.c +++ b/drivers/ata/sata_uli.c @@ -36,7 +36,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_uli" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.1" enum { uli_5289 = 0, diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index baca6d79bb0..598e6a26a48 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -46,7 +46,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_via" -#define DRV_VERSION "2.0" +#define DRV_VERSION "2.1" enum board_ids_enum { vt6420, @@ -60,7 +60,7 @@ enum { SATA_PATA_SHARING = 0x49, /* PATA/SATA sharing func ctrl */ PATA_UDMA_TIMING = 0xB3, /* PATA timing for DMA/ cable detect */ PATA_PIO_TIMING = 0xAB, /* PATA timing register */ - + PORT0 = (1 << 1), PORT1 = (1 << 0), ALL_PORTS = PORT0 | PORT1, @@ -151,7 +151,7 @@ static const struct ata_port_operations vt6420_sata_ops = { static const struct ata_port_operations vt6421_pata_ops = { .port_disable = ata_port_disable, - + .set_piomode = vt6421_set_pio_mode, .set_dmamode = vt6421_set_dma_mode, @@ -185,7 +185,7 @@ static const struct ata_port_operations vt6421_pata_ops = { static const struct ata_port_operations vt6421_sata_ops = { .port_disable = ata_port_disable, - + .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -423,16 +423,21 @@ static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev) { struct ata_probe_ent *probe_ent; struct ata_port_info *ppi[2]; - void __iomem * const *iomap; + void __iomem *bar5; ppi[0] = ppi[1] = &vt6420_port_info; probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) return NULL; - iomap = pcim_iomap_table(pdev); - probe_ent->port[0].scr_addr = svia_scr_addr(iomap[5], 0); - probe_ent->port[1].scr_addr = svia_scr_addr(iomap[5], 1); + bar5 = pcim_iomap(pdev, 5, 0); + if (!bar5) { + dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n"); + return NULL; + } + + probe_ent->port[0].scr_addr = svia_scr_addr(bar5, 0); + probe_ent->port[1].scr_addr = svia_scr_addr(bar5, 1); return probe_ent; } @@ -460,6 +465,13 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev) probe_ent->mwdma_mask = 0x07; probe_ent->udma_mask = 0x7f; + for (i = 0; i < 6; i++) + if (!pcim_iomap(pdev, i, 0)) { + dev_printk(KERN_ERR, &pdev->dev, + "failed to iomap PCI BAR %d\n", i); + return NULL; + } + for (i = 0; i < N_PORTS; i++) vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i); @@ -522,7 +534,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME); + rc = pci_request_regions(pdev, DRV_NAME); if (rc) { pcim_pin_device(pdev); return rc; diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 2fd037bde09..170bad1b415 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -47,7 +47,7 @@ #include <linux/libata.h> #define DRV_NAME "sata_vsc" -#define DRV_VERSION "2.0" +#define DRV_VERSION "2.1" enum { VSC_MMIO_BAR = 0, @@ -98,10 +98,6 @@ enum { VSC_SATA_INT_PHY_CHANGE), }; -#define is_vsc_sata_int_err(port_idx, int_status) \ - (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx))) - - static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) @@ -119,6 +115,28 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, } +static void vsc_freeze(struct ata_port *ap) +{ + void __iomem *mask_addr; + + mask_addr = ap->host->iomap[VSC_MMIO_BAR] + + VSC_SATA_INT_MASK_OFFSET + ap->port_no; + + writeb(0, mask_addr); +} + + +static void vsc_thaw(struct ata_port *ap) +{ + void __iomem *mask_addr; + + mask_addr = ap->host->iomap[VSC_MMIO_BAR] + + VSC_SATA_INT_MASK_OFFSET + ap->port_no; + + writeb(0xff, mask_addr); +} + + static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) { void __iomem *mask_addr; @@ -203,6 +221,36 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) } } +static inline void vsc_error_intr(u8 port_status, struct ata_port *ap) +{ + if (port_status & (VSC_SATA_INT_PHY_CHANGE | VSC_SATA_INT_ERROR_M)) + ata_port_freeze(ap); + else + ata_port_abort(ap); +} + +static void vsc_port_intr(u8 port_status, struct ata_port *ap) +{ + struct ata_queued_cmd *qc; + int handled = 0; + + if (unlikely(port_status & VSC_SATA_INT_ERROR)) { + vsc_error_intr(port_status, ap); + return; + } + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING))) + handled = ata_host_intr(ap, qc); + + /* We received an interrupt during a polled command, + * or some other spurious condition. Interrupt reporting + * with this hardware is fairly reliable so it is safe to + * simply clear the interrupt + */ + if (unlikely(!handled)) + ata_chk_status(ap); +} /* * vsc_sata_interrupt @@ -214,59 +262,36 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance) struct ata_host *host = dev_instance; unsigned int i; unsigned int handled = 0; - u32 int_status; - - spin_lock(&host->lock); + u32 status; - int_status = readl(host->iomap[VSC_MMIO_BAR] + - VSC_SATA_INT_STAT_OFFSET); + status = readl(host->iomap[VSC_MMIO_BAR] + VSC_SATA_INT_STAT_OFFSET); - for (i = 0; i < host->n_ports; i++) { - if (int_status & ((u32) 0xFF << (8 * i))) { - struct ata_port *ap; + if (unlikely(status == 0xffffffff || status == 0)) { + if (status) + dev_printk(KERN_ERR, host->dev, + ": IRQ status == 0xffffffff, " + "PCI fault or device removal?\n"); + goto out; + } - ap = host->ports[i]; + spin_lock(&host->lock); - if (is_vsc_sata_int_err(i, int_status)) { - u32 err_status; - printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__); - err_status = ap ? vsc_sata_scr_read(ap, SCR_ERROR) : 0; - vsc_sata_scr_write(ap, SCR_ERROR, err_status); - handled++; - } + for (i = 0; i < host->n_ports; i++) { + u8 port_status = (status >> (8 * i)) & 0xff; + if (port_status) { + struct ata_port *ap = host->ports[i]; if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { - struct ata_queued_cmd *qc; - - qc = ata_qc_from_tag(ap, ap->active_tag); - if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) - handled += ata_host_intr(ap, qc); - else if (is_vsc_sata_int_err(i, int_status)) { - /* - * On some chips (i.e. Intel 31244), an error - * interrupt will sneak in at initialization - * time (phy state changes). Clearing the SCR - * error register is not required, but it prevents - * the phy state change interrupts from recurring - * later. - */ - u32 err_status; - err_status = vsc_sata_scr_read(ap, SCR_ERROR); - printk(KERN_DEBUG "%s: clearing interrupt, " - "status %x; sata err status %x\n", - __FUNCTION__, - int_status, err_status); - vsc_sata_scr_write(ap, SCR_ERROR, err_status); - /* Clear interrupt status */ - ata_chk_status(ap); - handled++; - } - } + vsc_port_intr(port_status, ap); + handled++; + } else + dev_printk(KERN_ERR, host->dev, + ": interrupt from disabled port %d\n", i); } } spin_unlock(&host->lock); - +out: return IRQ_RETVAL(handled); } @@ -304,8 +329,8 @@ static const struct ata_port_operations vsc_sata_ops = { .qc_prep = ata_qc_prep, .qc_issue = ata_qc_issue_prot, .data_xfer = ata_data_xfer, - .freeze = ata_bmdma_freeze, - .thaw = ata_bmdma_thaw, + .freeze = vsc_freeze, + .thaw = vsc_thaw, .error_handler = ata_bmdma_error_handler, .post_internal_cmd = ata_bmdma_post_internal_cmd, .irq_handler = vsc_sata_interrupt, diff --git a/drivers/ata/sis.h b/drivers/ata/sis.h new file mode 100644 index 00000000000..231da8fc220 --- /dev/null +++ b/drivers/ata/sis.h @@ -0,0 +1,5 @@ + +struct ata_port_info; + +/* pata_sis.c */ +extern struct ata_port_info sis_info133; diff --git a/drivers/base/class.c b/drivers/base/class.c index 1417e5cd4c6..d5968128be2 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -840,48 +840,6 @@ void class_device_destroy(struct class *cls, dev_t devt) class_device_unregister(class_dev); } -int class_device_rename(struct class_device *class_dev, char *new_name) -{ - int error = 0; - char *old_class_name = NULL, *new_class_name = NULL; - - class_dev = class_device_get(class_dev); - if (!class_dev) - return -EINVAL; - - pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id, - new_name); - -#ifdef CONFIG_SYSFS_DEPRECATED - if (class_dev->dev) - old_class_name = make_class_name(class_dev->class->name, - &class_dev->kobj); -#endif - - strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); - - error = kobject_rename(&class_dev->kobj, new_name); - -#ifdef CONFIG_SYSFS_DEPRECATED - if (class_dev->dev) { - new_class_name = make_class_name(class_dev->class->name, - &class_dev->kobj); - if (new_class_name) - sysfs_create_link(&class_dev->dev->kobj, - &class_dev->kobj, new_class_name); - if (old_class_name) - sysfs_remove_link(&class_dev->dev->kobj, - old_class_name); - } -#endif - class_device_put(class_dev); - - kfree(old_class_name); - kfree(new_class_name); - - return error; -} - struct class_device * class_device_get(struct class_device *class_dev) { if (class_dev) diff --git a/drivers/base/core.c b/drivers/base/core.c index d04fd33dcd9..89ebe368272 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -637,12 +637,41 @@ int device_add(struct device *dev) BUS_NOTIFY_DEL_DEVICE, dev); device_remove_groups(dev); GroupError: - device_remove_attrs(dev); + device_remove_attrs(dev); AttrsError: if (dev->devt_attr) { device_remove_file(dev, dev->devt_attr); kfree(dev->devt_attr); } + + if (dev->class) { + sysfs_remove_link(&dev->kobj, "subsystem"); + /* If this is not a "fake" compatible device, remove the + * symlink from the class to the device. */ + if (dev->kobj.parent != &dev->class->subsys.kset.kobj) + sysfs_remove_link(&dev->class->subsys.kset.kobj, + dev->bus_id); +#ifdef CONFIG_SYSFS_DEPRECATED + if (parent) { + char *class_name = make_class_name(dev->class->name, + &dev->kobj); + if (class_name) + sysfs_remove_link(&dev->parent->kobj, + class_name); + kfree(class_name); + sysfs_remove_link(&dev->kobj, "device"); + } +#endif + + down(&dev->class->sem); + /* notify any interfaces that the device is now gone */ + list_for_each_entry(class_intf, &dev->class->interfaces, node) + if (class_intf->remove_dev) + class_intf->remove_dev(dev, class_intf); + /* remove the device from the class list */ + list_del_init(&dev->node); + up(&dev->class->sem); + } ueventattrError: device_remove_file(dev, &dev->uevent_attr); attrError: @@ -758,6 +787,13 @@ void device_del(struct device * dev) device_remove_attrs(dev); bus_remove_device(dev); + /* + * Some platform devices are driven without driver attached + * and managed resources may have been acquired. Make sure + * all resources are released. + */ + devres_release_all(dev); + /* Notify the platform of the removal, in case they * need to do anything... */ diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index cacb1c816e3..17ee97f3a99 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -406,22 +406,6 @@ config BLK_DEV_RAM_BLOCKSIZE setups function - apparently needed by the rd_load_image routine that supposes the filesystem in the image uses a 1024 blocksize. -config BLK_DEV_INITRD - bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support" - depends on BROKEN || !FRV - help - The initial RAM filesystem is a ramfs which is loaded by the - boot loader (loadlin or lilo) and that is mounted as root - before the normal boot procedure. It is typically used to - load modules needed to mount the "real" root file system, - etc. See <file:Documentation/initrd.txt> for details. - - If RAM disk support (BLK_DEV_RAM) is also included, this - also enables initial RAM disk (initrd) support and adds - 15 Kbytes (more on some other architectures) to the kernel size. - - If unsure say Y. - config CDROM_PKTCDVD tristate "Packet writing on CD/DVD media" depends on !UML diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index bb022ed4a86..8d17d8df366 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -530,7 +530,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) u16 aoemajor; hin = (struct aoe_hdr *) skb->mac.raw; - aoemajor = be16_to_cpu(hin->major); + aoemajor = be16_to_cpu(get_unaligned(&hin->major)); d = aoedev_by_aoeaddr(aoemajor, hin->minor); if (d == NULL) { snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " @@ -542,7 +542,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) spin_lock_irqsave(&d->lock, flags); - n = be32_to_cpu(hin->tag); + n = be32_to_cpu(get_unaligned(&hin->tag)); f = getframe(d, n); if (f == NULL) { calc_rttavg(d, -tsince(n)); @@ -550,9 +550,9 @@ aoecmd_ata_rsp(struct sk_buff *skb) snprintf(ebuf, sizeof ebuf, "%15s e%d.%d tag=%08x@%08lx\n", "unexpected rsp", - be16_to_cpu(hin->major), + be16_to_cpu(get_unaligned(&hin->major)), hin->minor, - be32_to_cpu(hin->tag), + be32_to_cpu(get_unaligned(&hin->tag)), jiffies); aoechr_error(ebuf); return; @@ -631,7 +631,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) printk(KERN_INFO "aoe: unrecognized ata command %2.2Xh for %d.%d\n", ahout->cmdstat, - be16_to_cpu(hin->major), + be16_to_cpu(get_unaligned(&hin->major)), hin->minor); } } @@ -733,7 +733,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb) * Enough people have their dip switches set backwards to * warrant a loud message for this special case. */ - aoemajor = be16_to_cpu(h->major); + aoemajor = be16_to_cpu(get_unaligned(&h->major)); if (aoemajor == 0xfff) { printk(KERN_ERR "aoe: Warning: shelf address is all ones. " "Check shelf dip switches.\n"); diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 9626e0f5da9..aab6d91a2c2 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -8,6 +8,7 @@ #include <linux/blkdev.h> #include <linux/netdevice.h> #include <linux/moduleparam.h> +#include <asm/unaligned.h> #include "aoe.h" #define NECODES 5 @@ -123,7 +124,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, skb_push(skb, ETH_HLEN); /* (1) */ h = (struct aoe_hdr *) skb->mac.raw; - n = be32_to_cpu(h->tag); + n = be32_to_cpu(get_unaligned(&h->tag)); if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) goto exit; @@ -133,7 +134,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, n = 0; if (net_ratelimit()) printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n", - be16_to_cpu(h->major), h->minor, + be16_to_cpu(get_unaligned(&h->major)), h->minor, h->err, aoe_errlist[n]); goto exit; } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 05dfe357527..0c716ee905d 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1291,13 +1291,19 @@ static void cciss_update_drive_info(int ctlr, int drv_index) if (inq_buff == NULL) goto mem_msg; + /* testing to see if 16-byte CDBs are already being used */ + if (h->cciss_read == CCISS_READ_16) { + cciss_read_capacity_16(h->ctlr, drv_index, 1, + &total_size, &block_size); + goto geo_inq; + } + cciss_read_capacity(ctlr, drv_index, 1, &total_size, &block_size); - /* total size = last LBA + 1 */ - /* FFFFFFFF + 1 = 0, cannot have a logical volume of size 0 */ - /* so we assume this volume this must be >2TB in size */ - if (total_size == (__u32) 0) { + /* if read_capacity returns all F's this volume is >2TB in size */ + /* so we switch to 16-byte CDB's for all read/write ops */ + if (total_size == 0xFFFFFFFFULL) { cciss_read_capacity_16(ctlr, drv_index, 1, &total_size, &block_size); h->cciss_read = CCISS_READ_16; @@ -1306,6 +1312,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index) h->cciss_read = CCISS_READ_10; h->cciss_write = CCISS_WRITE_10; } +geo_inq: cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, inq_buff, &h->drv[drv_index]); @@ -1917,13 +1924,14 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, drv->raid_level = inq_buff->data_byte[8]; } drv->block_size = block_size; - drv->nr_blocks = total_size; + drv->nr_blocks = total_size + 1; t = drv->heads * drv->sectors; if (t > 1) { - unsigned rem = sector_div(total_size, t); + sector_t real_size = total_size + 1; + unsigned long rem = sector_div(real_size, t); if (rem) - total_size++; - drv->cylinders = total_size; + real_size++; + drv->cylinders = real_size; } } else { /* Get geometry failed */ printk(KERN_WARNING "cciss: reading geometry failed\n"); @@ -1953,16 +1961,16 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, ctlr, buf, sizeof(ReadCapdata_struct), 1, logvol, 0, NULL, TYPE_CMD); if (return_code == IO_OK) { - *total_size = be32_to_cpu(*(__u32 *) buf->total_size)+1; + *total_size = be32_to_cpu(*(__u32 *) buf->total_size); *block_size = be32_to_cpu(*(__u32 *) buf->block_size); } else { /* read capacity command failed */ printk(KERN_WARNING "cciss: read capacity failed\n"); *total_size = 0; *block_size = BLOCK_SIZE; } - if (*total_size != (__u32) 0) + if (*total_size != 0) printk(KERN_INFO " blocks= %llu block_size= %d\n", - (unsigned long long)*total_size, *block_size); + (unsigned long long)*total_size+1, *block_size); kfree(buf); return; } @@ -1989,7 +1997,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, 1, logvol, 0, NULL, TYPE_CMD); } if (return_code == IO_OK) { - *total_size = be64_to_cpu(*(__u64 *) buf->total_size)+1; + *total_size = be64_to_cpu(*(__u64 *) buf->total_size); *block_size = be32_to_cpu(*(__u32 *) buf->block_size); } else { /* read capacity command failed */ printk(KERN_WARNING "cciss: read capacity failed\n"); @@ -1997,7 +2005,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, *block_size = BLOCK_SIZE; } printk(KERN_INFO " blocks= %llu block_size= %d\n", - (unsigned long long)*total_size, *block_size); + (unsigned long long)*total_size+1, *block_size); kfree(buf); return; } @@ -3119,8 +3127,9 @@ static void cciss_getgeometry(int cntl_num) } cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size); - /* total_size = last LBA + 1 */ - if(total_size == (__u32) 0) { + /* If read_capacity returns all F's the logical is >2TB */ + /* so we switch to 16-byte CDBs for all read/write ops */ + if(total_size == 0xFFFFFFFFULL) { cciss_read_capacity_16(cntl_num, i, 0, &total_size, &block_size); hba[cntl_num]->cciss_read = CCISS_READ_16; @@ -3395,7 +3404,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, return -1; } -static void __devexit cciss_remove_one(struct pci_dev *pdev) +static void cciss_remove_one(struct pci_dev *pdev) { ctlr_info_t *tmp_ptr; int i, j; @@ -3419,9 +3428,10 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev) memset(flush_buf, 0, 4); return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL, TYPE_CMD); - if (return_code != IO_OK) { - printk(KERN_WARNING "Error Flushing cache on controller %d\n", - i); + if (return_code == IO_OK) { + printk(KERN_INFO "Completed flushing cache on controller %d\n", i); + } else { + printk(KERN_WARNING "Error flushing cache on controller %d\n", i); } free_irq(hba[i]->intr[2], hba[i]); @@ -3472,6 +3482,7 @@ static struct pci_driver cciss_pci_driver = { .probe = cciss_init_one, .remove = __devexit_p(cciss_remove_one), .id_table = cciss_pci_device_id, /* id_table */ + .shutdown = cciss_remove_one, }; /* diff --git a/drivers/block/umem.c b/drivers/block/umem.c index dff3766f117..5872036e8ae 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -1179,8 +1179,10 @@ static int __init mm_init(void) return -ENOMEM; err = major_nr = register_blkdev(0, "umem"); - if (err < 0) + if (err < 0) { + pci_unregister_driver(&mm_pci_driver); return -EIO; + } for (i = 0; i < num_cards; i++) { mm_gendisk[i] = alloc_disk(1 << MM_SHIFT); @@ -1207,6 +1209,7 @@ static int __init mm_init(void) return 0; out: + pci_unregister_driver(&mm_pci_driver); unregister_blkdev(major_nr, "umem"); while (i--) put_disk(mm_gendisk[i]); diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 9256985cbe3..8919ccf8274 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -307,3 +307,5 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("BCM2033-MD.hex"); +MODULE_FIRMWARE("BCM2033-FW.bin"); diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 27cceb6f565..4c766f36d88 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -801,3 +801,4 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("bfubase.frm"); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 34e5555cb91..18b0f3992c5 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -63,6 +63,7 @@ MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>"); MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("BT3CPCC.bin"); diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index dc13ebacedf..44cd7b2ddf0 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -376,6 +376,25 @@ static int send_request(struct request *req) return 0; } +static void viocd_end_request(struct request *req, int uptodate) +{ + int nsectors = req->hard_nr_sectors; + + /* + * Make sure it's fully ended, and ensure that we process + * at least one sector. + */ + if (blk_pc_request(req)) + nsectors = (req->data_len + 511) >> 9; + if (!nsectors) + nsectors = 1; + + if (end_that_request_first(req, uptodate, nsectors)) + BUG(); + add_disk_randomness(req->rq_disk); + blkdev_dequeue_request(req); + end_that_request_last(req, uptodate); +} static int rwreq; @@ -385,11 +404,11 @@ static void do_viocd_request(request_queue_t *q) while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) { if (!blk_fs_request(req)) - end_request(req, 0); + viocd_end_request(req, 0); else if (send_request(req) < 0) { printk(VIOCD_KERN_WARNING "unable to send message to OS/400!"); - end_request(req, 0); + viocd_end_request(req, 0); } else rwreq++; } @@ -601,9 +620,9 @@ return_complete: "with rc %d:0x%04X: %s\n", req, event->xRc, bevent->sub_result, err->msg); - end_request(req, 0); + viocd_end_request(req, 0); } else - end_request(req, 1); + viocd_end_request(req, 1); /* restart handling of incoming requests */ spin_unlock_irqrestore(&viocd_reqlock, flags); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d0a6dc53213..3429ece4ef9 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1026,16 +1026,17 @@ config MMTIMER source "drivers/char/tpm/Kconfig" config TELCLOCK - tristate "Telecom clock driver for MPBL0010 ATCA SBC" + tristate "Telecom clock driver for ATCA SBC" depends on EXPERIMENTAL && X86 default n help - The telecom clock device is specific to the MPBL0010 ATCA computer and - allows direct userspace access to the configuration of the telecom clock - configuration settings. This device is used for hardware synchronization - across the ATCA backplane fabric. Upon loading, the driver exports a - sysfs directory, /sys/devices/platform/telco_clock, with a number of - files for controlling the behavior of this hardware. + The telecom clock device is specific to the MPCBL0010 and MPCBL0050 + ATCA computers and allows direct userspace access to the + configuration of the telecom clock configuration settings. This + device is used for hardware synchronization across the ATCA backplane + fabric. Upon loading, the driver exports a sysfs directory, + /sys/devices/platform/telco_clock, with a number of files for + controlling the behavior of this hardware. endmenu diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index a0d04a23dac..627f542827c 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -1,7 +1,8 @@ agpgart-y := backend.o frontend.o generic.o isoch.o +agpgart-$(CONFIG_COMPAT) += compat_ioctl.o + obj-$(CONFIG_AGP) += agpgart.o -obj-$(CONFIG_COMPAT) += compat_ioctl.o obj-$(CONFIG_AGP_ALI) += ali-agp.o obj-$(CONFIG_AGP_ATI) += ati-agp.o obj-$(CONFIG_AGP_AMD) += amd-k7-agp.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 9bd68d9f0f5..fdbca25a394 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -93,12 +93,12 @@ struct aper_size_info_fixed { struct agp_bridge_driver { struct module *owner; - void *aperture_sizes; + const void *aperture_sizes; int num_aperture_sizes; enum aper_size_type size_type; int cant_use_aperture; int needs_scratch_page; - struct gatt_mask *masks; + const struct gatt_mask *masks; int (*fetch_size)(void); int (*configure)(void); void (*agp_enable)(struct agp_bridge_data *, u32); @@ -119,7 +119,7 @@ struct agp_bridge_driver { struct agp_bridge_data { const struct agp_version *version; - struct agp_bridge_driver *driver; + const struct agp_bridge_driver *driver; struct vm_operations_struct *vm_ops; void *previous_size; void *current_size; @@ -290,7 +290,7 @@ void agp3_generic_cleanup(void); /* aperture sizes have been standardised since v3 */ #define AGP_GENERIC_SIZES_ENTRIES 11 -extern struct aper_size_info_16 agp3_generic_sizes[]; +extern const struct aper_size_info_16 agp3_generic_sizes[]; #define virt_to_gart(x) (phys_to_gart(virt_to_phys(x))) #define gart_to_virt(x) (phys_to_virt(gart_to_phys(x))) diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 98177a93076..5b684fddcc0 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -182,7 +182,7 @@ static void m1541_destroy_page(void * addr) /* Setup function */ -static struct aper_size_info_32 ali_generic_sizes[7] = +static const struct aper_size_info_32 ali_generic_sizes[7] = { {256, 65536, 6, 10}, {128, 32768, 5, 9}, @@ -193,7 +193,7 @@ static struct aper_size_info_32 ali_generic_sizes[7] = {4, 1024, 0, 3} }; -static struct agp_bridge_driver ali_generic_bridge = { +static const struct agp_bridge_driver ali_generic_bridge = { .owner = THIS_MODULE, .aperture_sizes = ali_generic_sizes, .size_type = U32_APER_SIZE, @@ -217,7 +217,7 @@ static struct agp_bridge_driver ali_generic_bridge = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver ali_m1541_bridge = { +static const struct agp_bridge_driver ali_m1541_bridge = { .owner = THIS_MODULE, .aperture_sizes = ali_generic_sizes, .size_type = U32_APER_SIZE, diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 3d8d448bf39..e6c534e6284 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -344,7 +344,7 @@ static int amd_remove_memory(struct agp_memory *mem, off_t pg_start, int type) return 0; } -static struct aper_size_info_lvl2 amd_irongate_sizes[7] = +static const struct aper_size_info_lvl2 amd_irongate_sizes[7] = { {2048, 524288, 0x0000000c}, {1024, 262144, 0x0000000a}, @@ -355,12 +355,12 @@ static struct aper_size_info_lvl2 amd_irongate_sizes[7] = {32, 8192, 0x00000000} }; -static struct gatt_mask amd_irongate_masks[] = +static const struct gatt_mask amd_irongate_masks[] = { {.mask = 1, .type = 0} }; -static struct agp_bridge_driver amd_irongate_driver = { +static const struct agp_bridge_driver amd_irongate_driver = { .owner = THIS_MODULE, .aperture_sizes = amd_irongate_sizes, .size_type = LVL2_APER_SIZE, diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 636d984ed4a..485720486d6 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -192,7 +192,7 @@ static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table) } -static struct aper_size_info_32 amd_8151_sizes[7] = +static const struct aper_size_info_32 amd_8151_sizes[7] = { {2048, 524288, 9, 0x00000000 }, /* 0 0 0 0 0 0 */ {1024, 262144, 8, 0x00000400 }, /* 1 0 0 0 0 0 */ @@ -232,7 +232,7 @@ static void amd64_cleanup(void) } -static struct agp_bridge_driver amd_8151_driver = { +static const struct agp_bridge_driver amd_8151_driver = { .owner = THIS_MODULE, .aperture_sizes = amd_8151_sizes, .size_type = U32_APER_SIZE, diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 77c9ad68fba..780e59e588a 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -24,7 +24,7 @@ #define ATI_GART_CACHE_ENTRY_CNTRL 0x10 -static struct aper_size_info_lvl2 ati_generic_sizes[7] = +static const struct aper_size_info_lvl2 ati_generic_sizes[7] = { {2048, 524288, 0x0000000c}, {1024, 262144, 0x0000000a}, @@ -410,7 +410,7 @@ static int ati_free_gatt_table(struct agp_bridge_data *bridge) return 0; } -static struct agp_bridge_driver ati_generic_bridge = { +static const struct agp_bridge_driver ati_generic_bridge = { .owner = THIS_MODULE, .aperture_sizes = ati_generic_sizes, .size_type = LVL2_APER_SIZE, diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 658cb1a72d2..df8da726285 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -59,7 +59,7 @@ static struct _efficeon_private { unsigned long l1_table[EFFICEON_L1_SIZE]; } efficeon_private; -static struct gatt_mask efficeon_generic_masks[] = +static const struct gatt_mask efficeon_generic_masks[] = { {.mask = 0x00000001, .type = 0} }; @@ -70,7 +70,7 @@ static inline unsigned long efficeon_mask_memory(unsigned long addr) return addr | 0x00000001; } -static struct aper_size_info_lvl2 efficeon_generic_sizes[4] = +static const struct aper_size_info_lvl2 efficeon_generic_sizes[4] = { {256, 65536, 0}, {128, 32768, 32}, @@ -309,7 +309,7 @@ static int efficeon_remove_memory(struct agp_memory * mem, off_t pg_start, int t } -static struct agp_bridge_driver efficeon_driver = { +static const struct agp_bridge_driver efficeon_driver = { .owner = THIS_MODULE, .aperture_sizes = efficeon_generic_sizes, .size_type = LVL2_APER_SIZE, diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 7923337c3d2..f902d71947b 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -1340,7 +1340,7 @@ void agp3_generic_cleanup(void) } EXPORT_SYMBOL(agp3_generic_cleanup); -struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES] = +const struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES] = { {4096, 1048576, 10,0x000}, {2048, 524288, 9, 0x800}, diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 847deabf7f9..bcdb149c817 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -419,7 +419,7 @@ hp_zx1_enable (struct agp_bridge_data *bridge, u32 mode) agp_device_command(command, (mode & AGP8X_MODE) != 0); } -struct agp_bridge_driver hp_zx1_driver = { +const struct agp_bridge_driver hp_zx1_driver = { .owner = THIS_MODULE, .size_type = FIXED_APER_SIZE, .configure = hp_zx1_configure, diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 3e7618653ab..53354bf83af 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -78,7 +78,7 @@ static struct { } *lp_desc; } i460; -static struct aper_size_info_8 i460_sizes[3] = +static const struct aper_size_info_8 i460_sizes[3] = { /* * The 32GB aperture is only available with a 4M GART page size. Due to the @@ -550,7 +550,7 @@ static unsigned long i460_mask_memory (struct agp_bridge_data *bridge, | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12); } -struct agp_bridge_driver intel_i460_driver = { +const struct agp_bridge_driver intel_i460_driver = { .owner = THIS_MODULE, .aperture_sizes = i460_sizes, .size_type = U8_APER_SIZE, diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 06b0bb6d982..e542a628f1c 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -63,7 +63,7 @@ extern int agp_memory_reserved; #define INTEL_I7505_AGPCTRL 0x70 #define INTEL_I7505_MCHCFG 0x50 -static struct aper_size_info_fixed intel_i810_sizes[] = +static const struct aper_size_info_fixed intel_i810_sizes[] = { {64, 16384, 4}, /* The 32M mode still requires a 64k gatt */ @@ -1365,18 +1365,18 @@ static int intel_7505_configure(void) } /* Setup function */ -static struct gatt_mask intel_generic_masks[] = +static const struct gatt_mask intel_generic_masks[] = { {.mask = 0x00000017, .type = 0} }; -static struct aper_size_info_8 intel_815_sizes[2] = +static const struct aper_size_info_8 intel_815_sizes[2] = { {64, 16384, 4, 0}, {32, 8192, 3, 8}, }; -static struct aper_size_info_8 intel_8xx_sizes[7] = +static const struct aper_size_info_8 intel_8xx_sizes[7] = { {256, 65536, 6, 0}, {128, 32768, 5, 32}, @@ -1387,7 +1387,7 @@ static struct aper_size_info_8 intel_8xx_sizes[7] = {4, 1024, 0, 63} }; -static struct aper_size_info_16 intel_generic_sizes[7] = +static const struct aper_size_info_16 intel_generic_sizes[7] = { {256, 65536, 6, 0}, {128, 32768, 5, 32}, @@ -1398,7 +1398,7 @@ static struct aper_size_info_16 intel_generic_sizes[7] = {4, 1024, 0, 63} }; -static struct aper_size_info_8 intel_830mp_sizes[4] = +static const struct aper_size_info_8 intel_830mp_sizes[4] = { {256, 65536, 6, 0}, {128, 32768, 5, 32}, @@ -1406,7 +1406,7 @@ static struct aper_size_info_8 intel_830mp_sizes[4] = {32, 8192, 3, 56} }; -static struct agp_bridge_driver intel_generic_driver = { +static const struct agp_bridge_driver intel_generic_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_generic_sizes, .size_type = U16_APER_SIZE, @@ -1430,7 +1430,7 @@ static struct agp_bridge_driver intel_generic_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver intel_810_driver = { +static const struct agp_bridge_driver intel_810_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i810_sizes, .size_type = FIXED_APER_SIZE, @@ -1455,7 +1455,7 @@ static struct agp_bridge_driver intel_810_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver intel_815_driver = { +static const struct agp_bridge_driver intel_815_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_815_sizes, .size_type = U8_APER_SIZE, @@ -1479,7 +1479,7 @@ static struct agp_bridge_driver intel_815_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver intel_830_driver = { +static const struct agp_bridge_driver intel_830_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, @@ -1504,7 +1504,7 @@ static struct agp_bridge_driver intel_830_driver = { .agp_type_to_mask_type = intel_i830_type_to_mask_type, }; -static struct agp_bridge_driver intel_820_driver = { +static const struct agp_bridge_driver intel_820_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_8xx_sizes, .size_type = U8_APER_SIZE, @@ -1528,7 +1528,7 @@ static struct agp_bridge_driver intel_820_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver intel_830mp_driver = { +static const struct agp_bridge_driver intel_830mp_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_830mp_sizes, .size_type = U8_APER_SIZE, @@ -1552,7 +1552,7 @@ static struct agp_bridge_driver intel_830mp_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver intel_840_driver = { +static const struct agp_bridge_driver intel_840_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_8xx_sizes, .size_type = U8_APER_SIZE, @@ -1576,7 +1576,7 @@ static struct agp_bridge_driver intel_840_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver intel_845_driver = { +static const struct agp_bridge_driver intel_845_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_8xx_sizes, .size_type = U8_APER_SIZE, @@ -1600,7 +1600,7 @@ static struct agp_bridge_driver intel_845_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver intel_850_driver = { +static const struct agp_bridge_driver intel_850_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_8xx_sizes, .size_type = U8_APER_SIZE, @@ -1624,7 +1624,7 @@ static struct agp_bridge_driver intel_850_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver intel_860_driver = { +static const struct agp_bridge_driver intel_860_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_8xx_sizes, .size_type = U8_APER_SIZE, @@ -1648,7 +1648,7 @@ static struct agp_bridge_driver intel_860_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver intel_915_driver = { +static const struct agp_bridge_driver intel_915_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, @@ -1673,7 +1673,7 @@ static struct agp_bridge_driver intel_915_driver = { .agp_type_to_mask_type = intel_i830_type_to_mask_type, }; -static struct agp_bridge_driver intel_i965_driver = { +static const struct agp_bridge_driver intel_i965_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, .size_type = FIXED_APER_SIZE, @@ -1698,7 +1698,7 @@ static struct agp_bridge_driver intel_i965_driver = { .agp_type_to_mask_type = intel_i830_type_to_mask_type, }; -static struct agp_bridge_driver intel_7505_driver = { +static const struct agp_bridge_driver intel_7505_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_8xx_sizes, .size_type = U8_APER_SIZE, diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 2563286b2fc..0c9dab557c9 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -272,7 +272,7 @@ static void nvidia_tlbflush(struct agp_memory *mem) } -static struct aper_size_info_8 nvidia_generic_sizes[5] = +static const struct aper_size_info_8 nvidia_generic_sizes[5] = { {512, 131072, 7, 0}, {256, 65536, 6, 8}, @@ -283,13 +283,13 @@ static struct aper_size_info_8 nvidia_generic_sizes[5] = }; -static struct gatt_mask nvidia_generic_masks[] = +static const struct gatt_mask nvidia_generic_masks[] = { { .mask = 1, .type = 0} }; -static struct agp_bridge_driver nvidia_driver = { +static const struct agp_bridge_driver nvidia_driver = { .owner = THIS_MODULE, .aperture_sizes = nvidia_generic_sizes, .size_type = U8_APER_SIZE, diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index b7b4590673a..3d83b461cca 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -210,7 +210,7 @@ parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode) agp_device_command(command, (mode & AGP8X_MODE) != 0); } -struct agp_bridge_driver parisc_agp_driver = { +static const struct agp_bridge_driver parisc_agp_driver = { .owner = THIS_MODULE, .size_type = FIXED_APER_SIZE, .configure = parisc_agp_configure, @@ -236,7 +236,7 @@ static int __init agp_ioc_init(void __iomem *ioc_regs) { struct _parisc_agp_info *info = &parisc_agp_info; - u64 *iova_base, *io_pdir, io_tlb_ps; + u64 iova_base, *io_pdir, io_tlb_ps; int io_tlb_shift; printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n"); diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 92d1dc45b9b..ee8f50edde1 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -247,7 +247,7 @@ static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev) return bridge; } -struct agp_bridge_driver sgi_tioca_driver = { +const struct agp_bridge_driver sgi_tioca_driver = { .owner = THIS_MODULE, .size_type = U16_APER_SIZE, .configure = sgi_tioca_configure, diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 60342b70815..125f4282d95 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -108,7 +108,7 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode) } } -static struct aper_size_info_8 sis_generic_sizes[7] = +static const struct aper_size_info_8 sis_generic_sizes[7] = { {256, 65536, 6, 99}, {128, 32768, 5, 83}, diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 9f5ae7714f8..55212a3811f 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -385,12 +385,12 @@ static int serverworks_remove_memory(struct agp_memory *mem, off_t pg_start, return 0; } -static struct gatt_mask serverworks_masks[] = +static const struct gatt_mask serverworks_masks[] = { {.mask = 1, .type = 0} }; -static struct aper_size_info_lvl2 serverworks_sizes[7] = +static const struct aper_size_info_lvl2 serverworks_sizes[7] = { {2048, 524288, 0x80000000}, {1024, 262144, 0xc0000000}, @@ -423,7 +423,7 @@ static void serverworks_agp_enable(struct agp_bridge_data *bridge, u32 mode) agp_device_command(command, 0); } -static struct agp_bridge_driver sworks_driver = { +static const struct agp_bridge_driver sworks_driver = { .owner = THIS_MODULE, .aperture_sizes = serverworks_sizes, .size_type = LVL2_APER_SIZE, diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 6c45702e542..91b062126a6 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -460,7 +460,7 @@ void null_cache_flush(void) /* Setup function */ -static struct aper_size_info_32 uninorth_sizes[7] = +static const struct aper_size_info_32 uninorth_sizes[7] = { #if 0 /* Not sure uninorth supports that high aperture sizes */ {256, 65536, 6, 64}, @@ -477,7 +477,7 @@ static struct aper_size_info_32 uninorth_sizes[7] = * Not sure that u3 supports that high aperture sizes but it * would strange if it did not :) */ -static struct aper_size_info_32 u3_sizes[8] = +static const struct aper_size_info_32 u3_sizes[8] = { {512, 131072, 7, 128}, {256, 65536, 6, 64}, @@ -489,7 +489,7 @@ static struct aper_size_info_32 u3_sizes[8] = {4, 1024, 0, 1} }; -struct agp_bridge_driver uninorth_agp_driver = { +const struct agp_bridge_driver uninorth_agp_driver = { .owner = THIS_MODULE, .aperture_sizes = (void *)uninorth_sizes, .size_type = U32_APER_SIZE, @@ -514,7 +514,7 @@ struct agp_bridge_driver uninorth_agp_driver = { .cant_use_aperture = 1, }; -struct agp_bridge_driver u3_agp_driver = { +const struct agp_bridge_driver u3_agp_driver = { .owner = THIS_MODULE, .aperture_sizes = (void *)u3_sizes, .size_type = U32_APER_SIZE, diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 2e7c04370cd..a2bb4eccaab 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -89,7 +89,7 @@ static void via_tlbflush(struct agp_memory *mem) } -static struct aper_size_info_8 via_generic_sizes[9] = +static const struct aper_size_info_8 via_generic_sizes[9] = { {256, 65536, 6, 0}, {128, 32768, 5, 128}, @@ -170,7 +170,7 @@ static void via_tlbflush_agp3(struct agp_memory *mem) } -static struct agp_bridge_driver via_agp3_driver = { +static const struct agp_bridge_driver via_agp3_driver = { .owner = THIS_MODULE, .aperture_sizes = agp3_generic_sizes, .size_type = U8_APER_SIZE, @@ -194,7 +194,7 @@ static struct agp_bridge_driver via_agp3_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_bridge_driver via_driver = { +static const struct agp_bridge_driver via_driver = { .owner = THIS_MODULE, .aperture_sizes = via_generic_sizes, .size_type = U8_APER_SIZE, diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 54df35527bc..16dc5d1d3cb 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -3501,6 +3501,7 @@ get_serial_info(struct cyclades_port *info, tmp.irq = cinfo->irq; tmp.flags = info->flags; tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; tmp.baud_base = info->baud; tmp.custom_divisor = info->custom_divisor; tmp.hub6 = 0; /*!!! */ diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c index 6d58b037080..59146e3365b 100644 --- a/drivers/char/ds1286.c +++ b/drivers/char/ds1286.c @@ -197,6 +197,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file, hrs = alm_tm.tm_hour; min = alm_tm.tm_min; + sec = alm_tm.tm_sec; if (hrs >= 24) hrs = 0xff; @@ -204,9 +205,11 @@ static int ds1286_ioctl(struct inode *inode, struct file *file, if (min >= 60) min = 0xff; - BIN_TO_BCD(sec); - BIN_TO_BCD(min); - BIN_TO_BCD(hrs); + if (sec != 0) + return -EINVAL; + + min = BIN2BCD(min); + min = BIN2BCD(hrs); spin_lock(&ds1286_lock); rtc_write(hrs, RTC_HOURS_ALARM); diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 88fc24fc439..de5be30484a 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -209,7 +209,6 @@ static void digi_send_break(struct channel *ch, int msec); static void setup_empty_event(struct tty_struct *tty, struct channel *ch); void epca_setup(char *, int *); -static int get_termio(struct tty_struct *, struct termio __user *); static int pc_write(struct tty_struct *, const unsigned char *, int); static int pc_init(void); static int init_PCI(void); @@ -2362,15 +2361,6 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, switch (cmd) { /* Begin switch cmd */ - -#if 0 /* Handled by calling layer properly */ - case TCGETS: - if (copy_to_user(argp, tty->termios, sizeof(struct ktermios))) - return -EFAULT; - return 0; - case TCGETA: - return get_termio(tty, argp); -#endif case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) @@ -2735,13 +2725,6 @@ static void setup_empty_event(struct tty_struct *tty, struct channel *ch) memoff(ch); } /* End setup_empty_event */ -/* --------------------- Begin get_termio ----------------------- */ - -static int get_termio(struct tty_struct * tty, struct termio __user * termio) -{ /* Begin get_termio */ - return kernel_termios_to_user_termio(termio, tty->termios); -} /* End get_termio */ - /* ---------------------- Begin epca_setup -------------------------- */ void epca_setup(char *str, int *ints) { /* Begin epca_setup */ diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index cc2cd46bedc..a0a88aa23f5 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -316,7 +316,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) { struct hvc_struct *hp; unsigned long flags; - int irq = NO_IRQ; + int irq = 0; int rc = 0; struct kobject *kobjp; @@ -338,14 +338,14 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) hp->tty = tty; /* Save for request_irq outside of spin_lock. */ irq = hp->irq; - if (irq != NO_IRQ) + if (irq) hp->irq_requested = 1; kobjp = &hp->kobj; spin_unlock_irqrestore(&hp->lock, flags); /* check error, fallback to non-irq */ - if (irq != NO_IRQ) + if (irq) rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp); /* @@ -373,7 +373,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) { struct hvc_struct *hp; struct kobject *kobjp; - int irq = NO_IRQ; + int irq = 0; unsigned long flags; if (tty_hung_up_p(filp)) @@ -407,7 +407,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) */ tty_wait_until_sent(tty, HVC_CLOSE_WAIT); - if (irq != NO_IRQ) + if (irq) free_irq(irq, hp); } else { @@ -424,7 +424,7 @@ static void hvc_hangup(struct tty_struct *tty) { struct hvc_struct *hp = tty->driver_data; unsigned long flags; - int irq = NO_IRQ; + int irq = 0; int temp_open_count; struct kobject *kobjp; @@ -453,7 +453,7 @@ static void hvc_hangup(struct tty_struct *tty) irq = hp->irq; hp->irq_requested = 0; spin_unlock_irqrestore(&hp->lock, flags); - if (irq != NO_IRQ) + if (irq) free_irq(irq, hp); while(temp_open_count) { --temp_open_count; @@ -583,7 +583,7 @@ static int hvc_poll(struct hvc_struct *hp) /* If we aren't interrupt driven and aren't throttled, we always * request a reschedule */ - if (hp->irq == NO_IRQ) + if (hp->irq == 0) poll_mask |= HVC_POLL_READ; /* Read data if any */ diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index a7b33d2f599..e22146546ad 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2478,6 +2478,11 @@ static __devinit void default_find_bmc(void) if (!info) return; +#ifdef CONFIG_PPC_MERGE + if (check_legacy_ioport(ipmi_defaults[i].port)) + continue; +#endif + info->addr_source = NULL; info->si_type = ipmi_defaults[i].type; diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 0e82968c2f3..f2e4ec4fd40 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -273,6 +273,7 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, DEBUGP(6, dev, "BytesToRead=%lu\n", bytes_to_read); min_bytes_to_read = min(count, bytes_to_read + 5); + min_bytes_to_read = min_t(size_t, min_bytes_to_read, READ_WRITE_BUFFER_SIZE); DEBUGP(6, dev, "Min=%lu\n", min_bytes_to_read); @@ -340,7 +341,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, return 0; } - if (count < 5) { + if ((count < 5) || (count > READ_WRITE_BUFFER_SIZE)) { DEBUGP(2, dev, "<- cm4040_write buffersize=%Zd < 5\n", count); return -EIO; } diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index f24c26d2dba..e4532685668 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1901,6 +1901,20 @@ static int init_dev(struct tty_driver *driver, int idx, /* check whether we're reopening an existing tty */ if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { tty = devpts_get_tty(idx); + /* + * If we don't have a tty here on a slave open, it's because + * the master already started the close process and there's + * no relation between devpts file and tty anymore. + */ + if (!tty && driver->subtype == PTY_TYPE_SLAVE) { + retval = -EIO; + goto end_init; + } + /* + * It's safe from now on because init_dev() is called with + * tty_mutex held and release_dev() won't change tty->count + * or tty->flags without having to grab tty_mutex + */ if (tty && driver->subtype == PTY_TYPE_MASTER) tty = tty->link; } else { diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index ccaa6a39cb4..d42060ede93 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -214,4 +214,7 @@ pm_good: return clocksource_register(&clocksource_acpi_pm); } -module_init(init_acpi_pm_clocksource); +/* We use fs_initcall because we want the PCI fixups to have run + * but we still need to load before device_initcall + */ +fs_initcall(init_acpi_pm_clocksource); diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c index 4f3925ceb36..1bde303b970 100644 --- a/drivers/clocksource/cyclone.c +++ b/drivers/clocksource/cyclone.c @@ -116,4 +116,4 @@ static int __init init_cyclone_clocksource(void) return clocksource_register(&clocksource_cyclone); } -module_init(init_cyclone_clocksource); +arch_initcall(init_cyclone_clocksource); diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index a44db75bc25..a905f782033 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -128,7 +128,7 @@ EXPORT_SYMBOL_GPL(cn_netlink_send); */ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data) { - struct cn_callback_entry *__cbq; + struct cn_callback_entry *__cbq, *__new_cbq; struct cn_dev *dev = &cdev; int err = -ENODEV; @@ -148,27 +148,27 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v } else { struct cn_callback_data *d; - __cbq = kzalloc(sizeof(*__cbq), GFP_ATOMIC); - if (__cbq) { - d = &__cbq->data; + err = -ENOMEM; + __new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC); + if (__new_cbq) { + d = &__new_cbq->data; d->callback_priv = msg; d->callback = __cbq->data.callback; d->ddata = data; d->destruct_data = destruct_data; - d->free = __cbq; + d->free = __new_cbq; - INIT_WORK(&__cbq->work, + INIT_WORK(&__new_cbq->work, &cn_queue_wrapper); - + if (queue_work(dev->cbdev->cn_queue, - &__cbq->work)) + &__new_cbq->work)) err = 0; else { - kfree(__cbq); + kfree(__new_cbq); err = -EINVAL; } - } else - err = -ENOMEM; + } } break; } diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index d60bcb9d14c..8d053f500fc 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -432,9 +432,6 @@ static void do_dbs_timer(struct work_struct *work) /* We want all CPUs to do sampling nearly on same jiffy */ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); - /* Permit rescheduling of this work item */ - work_release(work); - delay -= jiffies % delay; if (lock_policy_rwsem_write(cpu) < 0) @@ -473,7 +470,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) dbs_info->enable = 1; ondemand_powersave_bias_init(); dbs_info->sample_type = DBS_NORMAL_SAMPLE; - INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer); + INIT_DELAYED_WORK(&dbs_info->work, do_dbs_timer); queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work, delay); } diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 0eb62841e9b..6d3840e629d 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -99,9 +99,8 @@ do_crypt(void *src, void *dst, int len, u32 flags) static unsigned int geode_aes_crypt(struct geode_aes_op *op) { - u32 flags = 0; - int iflags; + unsigned long iflags; if (op->len == 0 || op->src == op->dst) return 0; diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 7452399501b..f4ee1afe488 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -667,7 +667,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size) if (item.format != HID_ITEM_FORMAT_SHORT) { dbg("unexpected long global item"); - kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; @@ -676,7 +675,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size) if (dispatch_type[item.type](parser, &item)) { dbg("item %u %u %u %u parsing failed\n", item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); - kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; @@ -685,14 +683,12 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size) if (start == end) { if (parser->collection_stack_ptr) { dbg("unbalanced collection at end of report description"); - kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; } if (parser->local.delimiter_depth) { dbg("unbalanced delimiter at end of report description"); - kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; @@ -703,7 +699,6 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size) } dbg("item fetching failed at offset %d\n", (int)(end - start)); - kfree(device->collection); hid_free_device(device); kfree(parser); return NULL; @@ -880,7 +875,7 @@ static void hid_output_field(struct hid_field *field, __u8 *data) /* make sure the unused bits in the last byte are zeros */ if (count > 0 && size > 0) - data[(count*size-1)/8] = 0; + data[(offset+count*size-1)/8] = 0; for (n = 0; n < count; n++) { if (field->logical_minimum < 0) /* signed values */ diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index 89241be4ec9..83c4126b37c 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -29,6 +29,7 @@ */ #include <linux/hid.h> +#include <linux/hid-debug.h> struct hid_usage_entry { unsigned page; diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 25d180a24fc..c8434023ba6 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -2,7 +2,7 @@ * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ * * Copyright (c) 2000-2001 Vojtech Pavlik - * Copyright (c) 2006 Jiri Kosina + * Copyright (c) 2006-2007 Jiri Kosina * * HID to Linux Input mapping */ @@ -71,7 +71,6 @@ static const struct { #define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0) #define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) -#define map_rel_clear(c) do { map_rel(c); clear_bit(c, bit); } while (0) #define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) #ifdef CONFIG_USB_HIDINPUT_POWERBOOK @@ -296,7 +295,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel } } - map_key_clear(code); + map_key(code); break; @@ -347,9 +346,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: if (field->flags & HID_MAIN_ITEM_RELATIVE) - map_rel_clear(usage->hid & 0xf); + map_rel(usage->hid & 0xf); else - map_abs_clear(usage->hid & 0xf); + map_abs(usage->hid & 0xf); break; case HID_GD_HATSWITCH: @@ -519,7 +518,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x22f: map_key_clear(KEY_ZOOMRESET); break; case 0x233: map_key_clear(KEY_SCROLLUP); break; case 0x234: map_key_clear(KEY_SCROLLDOWN); break; - case 0x238: map_rel_clear(REL_HWHEEL); break; + case 0x238: map_rel(REL_HWHEEL); break; case 0x25f: map_key_clear(KEY_CANCEL); break; case 0x279: map_key_clear(KEY_REDO); break; @@ -532,6 +531,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case 0x302: map_key_clear(KEY_PROG2); break; case 0x303: map_key_clear(KEY_PROG3); break; + /* Reported on Logitech S510 wireless keyboard */ + case 0x101f: map_key_clear(KEY_ZOOMIN); break; + case 0x1020: map_key_clear(KEY_ZOOMOUT); break; + case 0x1021: map_key_clear(KEY_ZOOMRESET); break; + /* this one is marked as 'Rotate' */ + case 0x1028: map_key_clear(KEY_ANGLE); break; + case 0x1029: map_key_clear(KEY_SHUFFLE); break; + case 0x1041: map_key_clear(KEY_BATTERY); break; + case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break; + case 0x1043: map_key_clear(KEY_SPREADSHEET); break; + case 0x1044: map_key_clear(KEY_PRESENTATION); break; + case 0x1045: map_key_clear(KEY_UNDO); break; + case 0x1046: map_key_clear(KEY_REDO); break; + case 0x1047: map_key_clear(KEY_PRINT); break; + case 0x1048: map_key_clear(KEY_SAVE); break; + case 0x1049: map_key_clear(KEY_PROG1); break; + case 0x104a: map_key_clear(KEY_PROG2); break; + case 0x104b: map_key_clear(KEY_PROG3); break; + case 0x104c: map_key_clear(KEY_PROG4); break; + default: goto ignore; } break; @@ -647,6 +666,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel set_bit(usage->type, input->evbit); + if (device->quirks & HID_QUIRK_DUPLICATE_USAGES && + (usage->type == EV_KEY || + usage->type == EV_REL || + usage->type == EV_ABS)) + clear_bit(usage->code, bit); + while (usage->code <= max && test_and_set_bit(usage->code, bit)) usage->code = find_next_zero_bit(bit, max + 1, usage->code); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 4d44a2db29d..fb19dbb31e4 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -495,6 +495,16 @@ config I2C_VERSATILE This driver can also be built as a module. If so, the module will be called i2c-versatile. +config I2C_ACORN + bool "Acorn IOC/IOMD I2C bus support" + depends on I2C && ARCH_ACORN + default y + select I2C_ALGOBIT + help + Say yes if you want to support the I2C bus on Acorn platforms. + + If you don't know, say Y. + config I2C_VIA tristate "VIA 82C586B" depends on I2C && PCI && EXPERIMENTAL diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 03505aa44bb..290b5401835 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o +obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_VIA) += i2c-via.o obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o obj-$(CONFIG_I2C_VOODOO3) += i2c-voodoo3.o diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c new file mode 100644 index 00000000000..09bd7f40b90 --- /dev/null +++ b/drivers/i2c/busses/i2c-acorn.c @@ -0,0 +1,97 @@ +/* + * linux/drivers/acorn/char/i2c.c + * + * Copyright (C) 2000 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. + * + * ARM IOC/IOMD i2c driver. + * + * On Acorn machines, the following i2c devices are on the bus: + * - PCF8583 real time clock & static RAM + */ +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/hardware/ioc.h> +#include <asm/system.h> + +#define FORCE_ONES 0xdc +#define SCL 0x02 +#define SDA 0x01 + +/* + * We must preserve all non-i2c output bits in IOC_CONTROL. + * Note also that we need to preserve the value of SCL and + * SDA outputs as well (which may be different from the + * values read back from IOC_CONTROL). + */ +static u_int force_ones; + +static void ioc_setscl(void *data, int state) +{ + u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); + u_int ones = force_ones; + + if (state) + ones |= SCL; + else + ones &= ~SCL; + + force_ones = ones; + + ioc_writeb(ioc_control | ones, IOC_CONTROL); +} + +static void ioc_setsda(void *data, int state) +{ + u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); + u_int ones = force_ones; + + if (state) + ones |= SDA; + else + ones &= ~SDA; + + force_ones = ones; + + ioc_writeb(ioc_control | ones, IOC_CONTROL); +} + +static int ioc_getscl(void *data) +{ + return (ioc_readb(IOC_CONTROL) & SCL) != 0; +} + +static int ioc_getsda(void *data) +{ + return (ioc_readb(IOC_CONTROL) & SDA) != 0; +} + +static struct i2c_algo_bit_data ioc_data = { + .setsda = ioc_setsda, + .setscl = ioc_setscl, + .getsda = ioc_getsda, + .getscl = ioc_getscl, + .udelay = 80, + .timeout = 100 +}; + +static struct i2c_adapter ioc_ops = { + .id = I2C_HW_B_IOC, + .algo_data = &ioc_data, +}; + +static int __init i2c_ioc_init(void) +{ + force_ones = FORCE_ONES | SCL | SDA; + + return i2c_bit_add_bus(&ioc_ops); +} + +__initcall(i2c_ioc_init); diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 49234e32fd1..5d134bb75ba 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -1023,7 +1023,7 @@ config BLK_DEV_4DRIVES config BLK_DEV_ALI14XX tristate "ALI M14xx support" help - This driver is enabled at runtime using the "ide0=ali14xx" kernel + This driver is enabled at runtime using the "ali14xx.probe" kernel boot parameter. It enables support for the secondary IDE interface of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster I/O speeds to be set as well. See the files @@ -1033,7 +1033,7 @@ config BLK_DEV_ALI14XX config BLK_DEV_DTC2278 tristate "DTC-2278 support" help - This driver is enabled at runtime using the "ide0=dtc2278" kernel + This driver is enabled at runtime using the "dtc2278.probe" kernel boot parameter. It enables support for the secondary IDE interface of the DTC-2278 card, and permits faster I/O speeds to be set as well. See the <file:Documentation/ide.txt> and @@ -1042,7 +1042,7 @@ config BLK_DEV_DTC2278 config BLK_DEV_HT6560B tristate "Holtek HT6560B support" help - This driver is enabled at runtime using the "ide0=ht6560b" kernel + This driver is enabled at runtime using the "ht6560b.probe" kernel boot parameter. It enables support for the secondary IDE interface of the Holtek card, and permits faster I/O speeds to be set as well. See the <file:Documentation/ide.txt> and @@ -1051,7 +1051,7 @@ config BLK_DEV_HT6560B config BLK_DEV_QD65XX tristate "QDI QD65xx support" help - This driver is enabled at runtime using the "ide0=qd65xx" kernel + This driver is enabled at runtime using the "qd65xx.probe" kernel boot parameter. It permits faster I/O speeds to be set. See the <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for more info. @@ -1059,7 +1059,7 @@ config BLK_DEV_QD65XX config BLK_DEV_UMC8672 tristate "UMC-8672 support" help - This driver is enabled at runtime using the "ide0=umc8672" kernel + This driver is enabled at runtime using the "umc8672.probe" kernel boot parameter. It enables support for the secondary IDE interface of the UMC-8672, and permits faster I/O speeds to be set as well. See the files <file:Documentation/ide.txt> and diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 6b2d152351b..556455fbfa2 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -17,8 +17,6 @@ * device can't do DMA handshaking for some stupid reason. We don't need to do that. */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/types.h> #include <linux/kernel.h> #include <linux/timer.h> diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index e2cea1889c4..37aa6ddd970 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -43,8 +43,6 @@ #define IDEDISK_VERSION "1.18" -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - //#define DEBUG #include <linux/module.h> diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index c67b3b1e6f4..bd513f5a232 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -583,6 +583,8 @@ u8 eighty_ninty_three (ide_drive_t *drive) if(!(drive->id->hw_config & 0x4000)) return 0; #endif /* CONFIG_IDEDMA_IVB */ + if (!(drive->id->hw_config & 0x2000)) + return 0; return 1; } diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 8afce4ceea3..68719314df3 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -345,16 +345,16 @@ static int ide_scan_pio_blacklist (char *model) /** * ide_get_best_pio_mode - get PIO mode from drive - * @driver: drive to consider + * @drive: drive to consider * @mode_wanted: preferred mode - * @max_mode: highest allowed - * @d: pio data + * @max_mode: highest allowed mode + * @d: PIO data * * This routine returns the recommended PIO settings for a given drive, * based on the drive->id information and the ide_pio_blacklist[]. - * This is used by most chipset support modules when "auto-tuning". * - * Drive PIO mode auto selection + * Drive PIO mode is auto-selected if 255 is passed as mode_wanted. + * This is used by most chipset support modules when "auto-tuning". */ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d) @@ -367,6 +367,7 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p if (mode_wanted != 255) { pio_mode = mode_wanted; + use_iordy = (pio_mode > 2); } else if (!drive->id) { pio_mode = 0; } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) { @@ -396,19 +397,12 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p } } -#if 0 - if (drive->id->major_rev_num & 0x0004) printk("ATA-2 "); -#endif - /* * Conservative "downgrade" for all pre-ATA2 drives */ if (pio_mode && pio_mode < 4) { pio_mode--; overridden = 1; -#if 0 - use_iordy = (pio_mode > 2); -#endif if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time) cycle_time = 0; /* use standard timing */ } diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 8afbd6cb94b..8f15c23aa70 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -31,8 +31,6 @@ * valid after probe time even with noprobe */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index b3c0818c5c6..dfbd7445852 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -126,8 +126,6 @@ #define REVISION "Revision: 7.00alpha2" #define VERSION "Id: ide.c 7.00a2 20020906" -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #define _IDE_C /* Tell ide.h it's really us */ #include <linux/module.h> @@ -1486,23 +1484,23 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m } #ifdef CONFIG_BLK_DEV_ALI14XX -static int __initdata probe_ali14xx; +extern int probe_ali14xx; extern int ali14xx_init(void); #endif #ifdef CONFIG_BLK_DEV_UMC8672 -static int __initdata probe_umc8672; +extern int probe_umc8672; extern int umc8672_init(void); #endif #ifdef CONFIG_BLK_DEV_DTC2278 -static int __initdata probe_dtc2278; +extern int probe_dtc2278; extern int dtc2278_init(void); #endif #ifdef CONFIG_BLK_DEV_HT6560B -static int __initdata probe_ht6560b; +extern int probe_ht6560b; extern int ht6560b_init(void); #endif #ifdef CONFIG_BLK_DEV_QD65XX -static int __initdata probe_qd65xx; +extern int probe_qd65xx; extern int qd65xx_init(void); #endif @@ -1580,7 +1578,7 @@ static int __init ide_setup(char *s) */ if (s[0] == 'h' && s[1] == 'd' && s[2] >= 'a' && s[2] <= max_drive) { const char *hd_words[] = { - "none", "noprobe", "nowerr", "cdrom", "serialize", + "none", "noprobe", "nowerr", "cdrom", "minus5", "autotune", "noautotune", "minus8", "swapdata", "bswap", "noflush", "remap", "remap63", "scsi", NULL }; unit = s[2] - 'a'; @@ -1608,9 +1606,6 @@ static int __init ide_setup(char *s) drive->ready_stat = 0; hwif->noprobe = 0; goto done; - case -5: /* "serialize" */ - printk(" -- USE \"ide%d=serialize\" INSTEAD", hw); - goto do_serialize; case -6: /* "autotune" */ drive->autotune = IDE_TUNE_AUTO; goto obsolete_option; @@ -1671,7 +1666,7 @@ static int __init ide_setup(char *s) * (-8, -9, -10) are reserved to ease the hardcoding. */ static const char *ide_words[] = { - "noprobe", "serialize", "autotune", "noautotune", + "noprobe", "serialize", "minus3", "minus4", "reset", "dma", "ata66", "minus8", "minus9", "minus10", "four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", NULL }; @@ -1742,12 +1737,17 @@ static int __init ide_setup(char *s) hwif->chipset = mate->chipset = ide_4drives; mate->irq = hwif->irq; memcpy(mate->io_ports, hwif->io_ports, sizeof(hwif->io_ports)); - goto do_serialize; + hwif->mate = mate; + mate->mate = hwif; + hwif->serialized = mate->serialized = 1; + goto obsolete_option; } #endif /* CONFIG_BLK_DEV_4DRIVES */ case -10: /* minus10 */ case -9: /* minus9 */ case -8: /* minus8 */ + case -4: + case -3: goto bad_option; case -7: /* ata66 */ #ifdef CONFIG_BLK_DEV_IDEPCI @@ -1762,16 +1762,7 @@ static int __init ide_setup(char *s) case -5: /* "reset" */ hwif->reset = 1; goto obsolete_option; - case -4: /* "noautotune" */ - hwif->drives[0].autotune = IDE_TUNE_NOAUTO; - hwif->drives[1].autotune = IDE_TUNE_NOAUTO; - goto obsolete_option; - case -3: /* "autotune" */ - hwif->drives[0].autotune = IDE_TUNE_AUTO; - hwif->drives[1].autotune = IDE_TUNE_AUTO; - goto obsolete_option; case -2: /* "serialize" */ - do_serialize: hwif->mate = &ide_hwifs[hw^1]; hwif->mate->mate = hwif; hwif->serialized = hwif->mate->serialized = 1; @@ -1840,8 +1831,8 @@ static void __init probe_for_hwifs (void) #endif /* CONFIG_BLK_DEV_CMD640 */ #ifdef CONFIG_BLK_DEV_IDE_PMAC { - extern void pmac_ide_probe(void); - pmac_ide_probe(); + extern int pmac_ide_probe(void); + (void)pmac_ide_probe(); } #endif /* CONFIG_BLK_DEV_IDE_PMAC */ #ifdef CONFIG_BLK_DEV_GAYLE diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c index 9c544467cb7..91961aa0304 100644 --- a/drivers/ide/legacy/ali14xx.c +++ b/drivers/ide/legacy/ali14xx.c @@ -37,8 +37,6 @@ * mode 4 for a while now with no trouble.) -Derek */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -230,9 +228,17 @@ static int __init ali14xx_probe(void) return 0; } +int probe_ali14xx = 0; + +module_param_named(probe, probe_ali14xx, bool, 0); +MODULE_PARM_DESC(probe, "probe for ALI M14xx chipsets"); + /* Can be called directly from ide.c. */ int __init ali14xx_init(void) { + if (probe_ali14xx == 0) + goto out; + /* auto-detect IDE controller port */ if (findPort()) { if (ali14xx_probe()) @@ -240,6 +246,7 @@ int __init ali14xx_init(void) return 0; } printk(KERN_ERR "ali14xx: not found.\n"); +out: return -ENODEV; } diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c index 3b1d33baaa2..0219ffa64db 100644 --- a/drivers/ide/legacy/dtc2278.c +++ b/drivers/ide/legacy/dtc2278.c @@ -4,8 +4,6 @@ * Copyright (C) 1996 Linus Torvalds & author (see below) */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -94,7 +92,7 @@ static void tune_dtc2278 (ide_drive_t *drive, u8 pio) HWIF(drive)->drives[!drive->select.b.unit].io_32bit = 1; } -static int __init probe_dtc2278(void) +static int __init dtc2278_probe(void) { unsigned long flags; ide_hwif_t *hwif, *mate; @@ -145,10 +143,18 @@ static int __init probe_dtc2278(void) return 0; } +int probe_dtc2278 = 0; + +module_param_named(probe, probe_dtc2278, bool, 0); +MODULE_PARM_DESC(probe, "probe for DTC2278xx chipsets"); + /* Can be called directly from ide.c. */ int __init dtc2278_init(void) { - if (probe_dtc2278()) { + if (probe_dtc2278 == 0) + return -ENODEV; + + if (dtc2278_probe()) { printk(KERN_ERR "dtc2278: ide interfaces already in use!\n"); return -EBUSY; } diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c index 19ccd006f20..a2832643c52 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/legacy/ht6560b.c @@ -36,8 +36,6 @@ #define HT6560B_VERSION "v0.07" -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -303,12 +301,20 @@ static void tune_ht6560b (ide_drive_t *drive, u8 pio) #endif } +int probe_ht6560b = 0; + +module_param_named(probe, probe_ht6560b, bool, 0); +MODULE_PARM_DESC(probe, "probe for HT6560B chipset"); + /* Can be called directly from ide.c. */ int __init ht6560b_init(void) { ide_hwif_t *hwif, *mate; int t; + if (probe_ht6560b == 0) + return -ENODEV; + hwif = &ide_hwifs[0]; mate = &ide_hwifs[1]; diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index a5023cdbdc5..b08c37c9f95 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -359,14 +359,17 @@ void ide_release(struct pcmcia_device *link) static struct pcmcia_device_id ide_ids[] = { PCMCIA_DEVICE_FUNC_ID(4), PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ + PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */ + PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */ PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), - PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), + PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */ PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */ PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), - PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */ + PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */ + PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */ PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74), PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9), diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c index d3c3bc2640e..2fb8f50f129 100644 --- a/drivers/ide/legacy/qd65xx.c +++ b/drivers/ide/legacy/qd65xx.c @@ -16,8 +16,8 @@ * Please set local bus speed using kernel parameter idebus * for example, "idebus=33" stands for 33Mhz VLbus * To activate controller support, use "ide0=qd65xx" - * To enable tuning, use "ide0=autotune" - * To enable second channel tuning (qd6580 only), use "ide1=autotune" + * To enable tuning, use "hda=autotune hdb=autotune" + * To enable 2nd channel tuning (qd6580 only), use "hdc=autotune hdd=autotune" */ /* @@ -25,8 +25,6 @@ * Samuel Thibault <samuel.thibault@fnac.net> */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -490,9 +488,17 @@ static int __init qd_probe(int base) return 1; } +int probe_qd65xx = 0; + +module_param_named(probe, probe_qd65xx, bool, 0); +MODULE_PARM_DESC(probe, "probe for QD65xx chipsets"); + /* Can be called directly from ide.c. */ int __init qd65xx_init(void) { + if (probe_qd65xx == 0) + return -ENODEV; + if (qd_probe(0x30)) qd_probe(0xb0); if (ide_hwifs[0].chipset != ide_qd65xx && diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c index 6e2c58c5f6a..ca797445557 100644 --- a/drivers/ide/legacy/umc8672.c +++ b/drivers/ide/legacy/umc8672.c @@ -165,12 +165,21 @@ static int __init umc8672_probe(void) return 0; } +int probe_umc8672 = 0; + +module_param_named(probe, probe_umc8672, bool, 0); +MODULE_PARM_DESC(probe, "probe for UMC8672 chipset"); + /* Can be called directly from ide.c. */ int __init umc8672_init(void) { - if (umc8672_probe()) - return -ENODEV; - return 0; + if (probe_umc8672 == 0) + goto out; + + if (umc8672_probe() == 0) + return 0;; +out: + return -ENODEV;; } #ifdef MODULE diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c index 0a59d5ef159..b2dc028dc8c 100644 --- a/drivers/ide/mips/au1xxx-ide.c +++ b/drivers/ide/mips/au1xxx-ide.c @@ -29,8 +29,6 @@ * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE * Interface and Linux Device Driver" Application Note. */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/types.h> #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index 4debd18d52f..83e0aa65a43 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/pci/alim15x3.c Version 0.17 2003/01/02 + * linux/drivers/ide/pci/alim15x3.c Version 0.21 2007/02/03 * * Copyright (C) 1998-2000 Michel Aubry, Maintainer * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer @@ -9,6 +9,7 @@ * May be copied or modified under the terms of the GNU General Public License * Copyright (C) 2002 Alan Cox <alan@redhat.com> * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw> + * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com> * * (U)DMA capable version of ali 1533/1543(C), 1535(D) * @@ -280,15 +281,17 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count) #endif /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_PROC_FS) */ /** - * ali15x3_tune_drive - set up a drive + * ali15x3_tune_pio - set up chipset for PIO mode * @drive: drive to tune - * @pio: unused + * @pio: desired mode * - * Select the best PIO timing for the drive in question. Then - * program the controller for this drive set up + * Select the best PIO mode for the drive in question. + * Then program the controller for this mode. + * + * Returns the PIO mode programmed. */ -static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio) +static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio) { ide_pio_data_t d; ide_hwif_t *hwif = HWIF(drive); @@ -356,6 +359,22 @@ static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio) * { 20, 50, 30 } PIO Mode 5 with IORDY (nonstandard) */ + return pio; +} + +/** + * ali15x3_tune_drive - set up drive for PIO mode + * @drive: drive to tune + * @pio: desired mode + * + * Program the controller with the best PIO timing for the given drive. + * Then set up the drive itself. + */ + +static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio) +{ + pio = ali15x3_tune_pio(drive, pio); + (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } /** @@ -430,7 +449,7 @@ static u8 ali15x3_ratemask (ide_drive_t *drive) } /** - * ali15x3_tune_chipset - set up chiset for new speed + * ali15x3_tune_chipset - set up chipset/drive for new speed * @drive: drive to configure for * @xferspeed: desired speed * @@ -461,7 +480,7 @@ static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed) pci_write_config_byte(dev, m5229_udma, tmpbyte); if (speed < XFER_SW_DMA_0) - ali15x3_tune_drive(drive, speed); + (void) ali15x3_tune_pio(drive, speed - XFER_PIO_0); } else { pci_read_config_byte(dev, m5229_udma, &tmpbyte); tmpbyte &= (0x0f << ((1-unit) << 2)); diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index 61b5f9c0b2f..dc43f009aca 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c @@ -98,7 +98,6 @@ * (patch courtesy of Zoltan Hidvegi) */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ #define CMD640_PREFETCH_MASKS 1 //#define CMD640_DUMP_REGS diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 49df27513da..b0d4825c56a 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -1,6 +1,6 @@ /* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16 * - * linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002 + * linux/drivers/ide/pci/cmd64x.c Version 1.41 Feb 3, 2007 * * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines. * Note, this driver is not used at all on other systems because @@ -12,6 +12,7 @@ * Copyright (C) 1998 David S. Miller (davem@redhat.com) * * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> + * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com> */ #include <linux/module.h> @@ -262,43 +263,25 @@ static void program_drive_counts (ide_drive_t *drive, int setup_count, int activ } /* - * Attempts to set the interface PIO mode. - * The preferred method of selecting PIO modes (e.g. mode 4) is - * "echo 'piomode:4' > /proc/ide/hdx/settings". Special cases are - * 8: prefetch off, 9: prefetch on, 255: auto-select best mode. - * Called with 255 at boot time. + * This routine selects drive's best PIO mode, calculates setup/active/recovery + * counts, and then writes them into the chipset registers. */ - -static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted) +static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted) { int setup_time, active_time, recovery_time; int clock_time, pio_mode, cycle_time; u8 recovery_count2, cycle_count; int setup_count, active_count, recovery_count; int bus_speed = system_bus_clock(); - /*byte b;*/ ide_pio_data_t d; - switch (mode_wanted) { - case 8: /* set prefetch off */ - case 9: /* set prefetch on */ - mode_wanted &= 1; - /*set_prefetch_mode(index, mode_wanted);*/ - cmdprintk("%s: %sabled cmd640 prefetch\n", - drive->name, mode_wanted ? "en" : "dis"); - return; - } - - mode_wanted = ide_get_best_pio_mode (drive, mode_wanted, 5, &d); - pio_mode = d.pio_mode; + pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &d); cycle_time = d.cycle_time; /* * I copied all this complicated stuff from cmd640.c and made a few * minor changes. For now I am just going to pray that it is correct. */ - if (pio_mode > 5) - pio_mode = 5; setup_time = ide_pio_timings[pio_mode].setup_time; active_time = ide_pio_timings[pio_mode].active_time; recovery_time = cycle_time - (setup_time + active_time); @@ -320,22 +303,33 @@ static void cmd64x_tuneproc (ide_drive_t *drive, u8 mode_wanted) if (active_count > 16) active_count = 16; /* maximum allowed by cmd646 */ - /* - * In a perfect world, we might set the drive pio mode here - * (using WIN_SETFEATURE) before continuing. - * - * But we do not, because: - * 1) this is the wrong place to do it - * (proper is do_special() in ide.c) - * 2) in practice this is rarely, if ever, necessary - */ program_drive_counts (drive, setup_count, active_count, recovery_count); - cmdprintk("%s: selected cmd646 PIO mode%d : %d (%dns)%s, " + cmdprintk("%s: PIO mode wanted %d, selected %d (%dns)%s, " "clocks=%d/%d/%d\n", - drive->name, pio_mode, mode_wanted, cycle_time, + drive->name, mode_wanted, pio_mode, cycle_time, d.overridden ? " (overriding vendor mode)" : "", setup_count, active_count, recovery_count); + + return pio_mode; +} + +/* + * Attempts to set drive's PIO mode. + * Special cases are 8: prefetch off, 9: prefetch on (both never worked), + * and 255: auto-select best mode (used at boot time). + */ +static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio) +{ + /* + * Filter out the prefetch control values + * to prevent PIO5 from being programmed + */ + if (pio == 8 || pio == 9) + return; + + pio = cmd64x_tune_pio(drive, pio); + (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); } static u8 cmd64x_ratemask (ide_drive_t *drive) @@ -387,22 +381,6 @@ static u8 cmd64x_ratemask (ide_drive_t *drive) return mode; } -static void config_cmd64x_chipset_for_pio (ide_drive_t *drive, u8 set_speed) -{ - u8 speed = 0x00; - u8 set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL); - - cmd64x_tuneproc(drive, set_pio); - speed = XFER_PIO_0 + set_pio; - if (set_speed) - (void) ide_config_drive_speed(drive, speed); -} - -static void config_chipset_for_pio (ide_drive_t *drive, u8 set_speed) -{ - config_cmd64x_chipset_for_pio(drive, set_speed); -} - static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); @@ -414,7 +392,7 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed) u8 speed = ide_rate_filter(cmd64x_ratemask(drive), xferspeed); - if (speed > XFER_PIO_4) { + if (speed >= XFER_SW_DMA_0) { (void) pci_read_config_byte(dev, pciD, ®D); (void) pci_read_config_byte(dev, pciU, ®U); regD &= ~(unit ? 0x40 : 0x20); @@ -438,17 +416,20 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed) case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; - case XFER_PIO_4: cmd64x_tuneproc(drive, 4); break; - case XFER_PIO_3: cmd64x_tuneproc(drive, 3); break; - case XFER_PIO_2: cmd64x_tuneproc(drive, 2); break; - case XFER_PIO_1: cmd64x_tuneproc(drive, 1); break; - case XFER_PIO_0: cmd64x_tuneproc(drive, 0); break; + case XFER_PIO_5: + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0); + break; default: return 1; } - if (speed > XFER_PIO_4) { + if (speed >= XFER_SW_DMA_0) { (void) pci_write_config_byte(dev, pciU, regU); regD |= (unit ? 0x40 : 0x20); (void) pci_write_config_byte(dev, pciD, regD); @@ -461,8 +442,6 @@ static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, cmd64x_ratemask(drive)); - config_chipset_for_pio(drive, !speed); - if (!speed) return 0; @@ -478,7 +457,7 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - config_chipset_for_pio(drive, 1); + cmd64x_tune_drive(drive, 255); return -1; } @@ -679,14 +658,13 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif) pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); class_rev &= 0xff; - hwif->tuneproc = &cmd64x_tuneproc; + hwif->tuneproc = &cmd64x_tune_drive; hwif->speedproc = &cmd64x_tune_chipset; - if (!hwif->dma_base) { - hwif->drives[0].autotune = 1; - hwif->drives[1].autotune = 1; + hwif->drives[0].autotune = hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) return; - } hwif->atapi_dma = 1; diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index e2672fc65d3..d4b753e7011 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -122,7 +122,7 @@ static struct pci_driver driver = { static int delkin_cb_init (void) { - return pci_module_init(&driver); + return pci_register_driver(&driver); } static void diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index b408c6c517e..f2c5a141ca1 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -21,8 +21,6 @@ * are deemed to be part of the source code. */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/types.h> #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 9ca60dd2185..aede7eee924 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -57,7 +57,7 @@ * There is a 25/33MHz switch in configuration * register, but driver is written for use at any frequency which get * (use idebus=xx to select PCI bus speed). - * Use ide0=autotune for automatical tune of the PIO modes. + * Use hda=autotune and hdb=autotune for automatical tune of the PIO modes. * If you get strange results, do not use this and set PIO manually * by hdparm. * @@ -87,7 +87,6 @@ * 0.5 doesn't work. */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ #define OPTI621_DEBUG /* define for debug messages */ #include <linux/types.h> diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 569822f4cf5..061d300ab8b 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c @@ -1,10 +1,10 @@ /* - * linux/drivers/ide/pci/piix.c Version 0.46 December 3, 2006 + * linux/drivers/ide/pci/piix.c Version 0.47 February 8, 2007 * * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2003 Red Hat Inc <alan@redhat.com> - * Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com> + * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com> * * May be copied or modified under the terms of the GNU General Public License * @@ -205,14 +205,13 @@ static u8 piix_dma_2_pio (u8 xfer_rate) { } /** - * piix_tune_drive - tune a drive attached to a PIIX + * piix_tune_pio - tune PIIX for PIO mode * @drive: drive to tune * @pio: desired PIO mode * - * Set the interface PIO mode based upon the settings done by AMI BIOS - * (might be useful if drive is not registered in CMOS for any reason). + * Set the interface PIO mode based upon the settings done by AMI BIOS. */ -static void piix_tune_drive (ide_drive_t *drive, u8 pio) +static void piix_tune_pio (ide_drive_t *drive, u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -233,8 +232,6 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) { 2, 1 }, { 2, 3 }, }; - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); - /* * Master vs slave is synchronized above us but the slave register is * shared by the two hwifs so the corner case of two slave timeouts in @@ -253,19 +250,20 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) master_data |= 0x4000; master_data &= ~0x0070; if (pio > 1) { - /* enable PPE, IE and TIME */ - master_data = master_data | (control << 4); + /* Set PPE, IE and TIME */ + master_data |= control << 4; } pci_read_config_byte(dev, slave_port, &slave_data); - slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); - slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); + slave_data &= hwif->channel ? 0x0f : 0xf0; + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << + (hwif->channel ? 4 : 0); } else { master_data &= ~0x3307; if (pio > 1) { /* enable PPE, IE and TIME */ - master_data = master_data | control; + master_data |= control; } - master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); + master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8); } pci_write_config_word(dev, master_port, master_data); if (is_slave) @@ -274,6 +272,21 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio) } /** + * piix_tune_drive - tune a drive attached to PIIX + * @drive: drive to tune + * @pio: desired PIO mode + * + * Set the drive's PIO mode (might be useful if drive is not registered + * in CMOS for any reason). + */ +static void piix_tune_drive (ide_drive_t *drive, u8 pio) +{ + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + piix_tune_pio(drive, pio); + (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); +} + +/** * piix_tune_chipset - tune a PIIX interface * @drive: IDE drive to tune * @xferspeed: speed to configure @@ -348,8 +361,8 @@ static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed) pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag); } - piix_tune_drive(drive, piix_dma_2_pio(speed)); - return (ide_config_drive_speed(drive, speed)); + piix_tune_pio(drive, piix_dma_2_pio(speed)); + return ide_config_drive_speed(drive, speed); } /** @@ -392,9 +405,7 @@ static int piix_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - /* Find best PIO mode. */ - piix_tune_chipset(drive, XFER_PIO_0 + - ide_get_best_pio_mode(drive, 255, 4, NULL)); + piix_tune_drive(drive, 255); return -1; } diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c index c1855311052..f8c95469014 100644 --- a/drivers/ide/pci/rz1000.c +++ b/drivers/ide/pci/rz1000.c @@ -15,8 +15,6 @@ * Dunno if this fixes both ports, or only the primary port (?). */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ - #include <linux/types.h> #include <linux/module.h> #include <linux/kernel.h> diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 7b4c189a9d9..71eccdf5f81 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -26,6 +26,11 @@ * If you have strange problems with nVidia chipset systems please * see the SI support documentation and update your system BIOS * if neccessary + * + * The Dell DRAC4 has some interesting features including effectively hot + * unplugging/replugging the virtual CD interface when the DRAC is reset. + * This often causes drivers/ide/siimage to panic but is ok with the rather + * smarter code in libata. */ #include <linux/types.h> diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c index ae7eb58d961..852ccb36da1 100644 --- a/drivers/ide/pci/slc90e66.c +++ b/drivers/ide/pci/slc90e66.c @@ -1,8 +1,8 @@ /* - * linux/drivers/ide/pci/slc90e66.c Version 0.13 December 30, 2006 + * linux/drivers/ide/pci/slc90e66.c Version 0.14 February 8, 2007 * * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com> + * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com> * * This is a look-alike variation of the ICH0 PIIX4 Ultra-66, * but this keeps the ISA-Bridge and slots alive. @@ -57,11 +57,7 @@ static u8 slc90e66_dma_2_pio (u8 xfer_rate) { } } -/* - * Based on settings done by AMI BIOS - * (might be useful if drive is not registered in CMOS for any reason). - */ -static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) +static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; @@ -80,7 +76,6 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) { 2, 1 }, { 2, 3 }, }; - pio = ide_get_best_pio_mode(drive, pio, 4, NULL); spin_lock_irqsave(&ide_lock, flags); pci_read_config_word(dev, master_port, &master_data); @@ -94,19 +89,20 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) master_data |= 0x4000; master_data &= ~0x0070; if (pio > 1) { - /* enable PPE, IE and TIME */ - master_data = master_data | (control << 4); + /* Set PPE, IE and TIME */ + master_data |= control << 4; } pci_read_config_byte(dev, slave_port, &slave_data); - slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0); - slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0)); + slave_data &= hwif->channel ? 0x0f : 0xf0; + slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << + (hwif->channel ? 4 : 0); } else { master_data &= ~0x3307; if (pio > 1) { /* enable PPE, IE and TIME */ - master_data = master_data | control; + master_data |= control; } - master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8); + master_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8); } pci_write_config_word(dev, master_port, master_data); if (is_slave) @@ -114,6 +110,13 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) spin_unlock_irqrestore(&ide_lock, flags); } +static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio) +{ + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + slc90e66_tune_pio(drive, pio); + (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio); +} + static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); @@ -162,8 +165,8 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed) pci_write_config_word(dev, 0x4a, reg4a & ~a_speed); } - slc90e66_tune_drive(drive, slc90e66_dma_2_pio(speed)); - return (ide_config_drive_speed(drive, speed)); + slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed)); + return ide_config_drive_speed(drive, speed); } static int slc90e66_config_drive_for_dma (ide_drive_t *drive) @@ -185,8 +188,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive) return 0; if (ide_use_fast_pio(drive)) - (void)slc90e66_tune_chipset(drive, XFER_PIO_0 + - ide_get_best_pio_mode(drive, 255, 4, NULL)); + slc90e66_tune_drive(drive, 255); return -1; } diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 395d35253d5..071a030ec26 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -48,7 +48,7 @@ #include <asm/mediabay.h> #endif -#include "ide-timing.h" +#include "../ide-timing.h" #undef IDE_PMAC_DEBUG @@ -1551,19 +1551,34 @@ static struct pci_driver pmac_ide_pci_driver = { }; MODULE_DEVICE_TABLE(pci, pmac_ide_pci_match); -void __init -pmac_ide_probe(void) +int __init pmac_ide_probe(void) { + int error; + if (!machine_is(powermac)) - return; + return -ENODEV; #ifdef CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST - pci_register_driver(&pmac_ide_pci_driver); - macio_register_driver(&pmac_ide_macio_driver); + error = pci_register_driver(&pmac_ide_pci_driver); + if (error) + goto out; + error = macio_register_driver(&pmac_ide_macio_driver); + if (error) { + pci_unregister_driver(&pmac_ide_pci_driver); + goto out; + } #else - macio_register_driver(&pmac_ide_macio_driver); - pci_register_driver(&pmac_ide_pci_driver); + error = macio_register_driver(&pmac_ide_macio_driver); + if (error) + goto out; + error = pci_register_driver(&pmac_ide_pci_driver); + if (error) { + macio_unregister_driver(&pmac_ide_macio_driver); + goto out; + } #endif +out: + return error; } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC @@ -1983,7 +1998,7 @@ static void pmac_ide_dma_host_off(ide_drive_t *drive) { } -static int pmac_ide_dma_host_on(ide_drive_t *drive) +static void pmac_ide_dma_host_on(ide_drive_t *drive) { } diff --git a/drivers/ide/ppc/scc_pata.c b/drivers/ide/ppc/scc_pata.c index de64b022478..f84bf791f72 100644 --- a/drivers/ide/ppc/scc_pata.c +++ b/drivers/ide/ppc/scc_pata.c @@ -509,6 +509,32 @@ static int scc_ide_dma_end(ide_drive_t * drive) return __ide_dma_end(drive); } +/* returns 1 if dma irq issued, 0 otherwise */ +static int scc_dma_test_irq(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + u8 dma_stat = hwif->INB(hwif->dma_status); + + /* return 1 if INTR asserted */ + if ((dma_stat & 4) == 4) + return 1; + + /* Workaround for PTERADD: emulate DMA_INTR when + * - IDE_STATUS[ERR] = 1 + * - INT_STATUS[INTRQ] = 1 + * - DMA_STATUS[IORACTA] = 1 + */ + if (in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT && + in_be32((void __iomem *)(hwif->dma_base + 0x014)) & INTSTS_INTRQ && + dma_stat & 1) + return 1; + + if (!drive->waiting_for_dma) + printk(KERN_WARNING "%s: (%s) called while not waiting\n", + drive->name, __FUNCTION__); + return 0; +} + /** * setup_mmio_scc - map CTRL/BMID region * @dev: PCI device we are configuring @@ -712,6 +738,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif) hwif->speedproc = scc_tune_chipset; hwif->tuneproc = scc_tuneproc; hwif->ide_dma_check = scc_config_drive_for_dma; + hwif->ide_dma_test_irq = scc_dma_test_irq; hwif->drives[0].autotune = IDE_TUNE_AUTO; hwif->drives[1].autotune = IDE_TUNE_AUTO; diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index d446998b12a..842cd0b53e9 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -88,7 +88,6 @@ struct cm_port { struct cm_device { struct list_head list; struct ib_device *device; - __be64 ca_guid; struct cm_port port[0]; }; @@ -739,8 +738,8 @@ retest: ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg); spin_unlock_irqrestore(&cm_id_priv->lock, flags); ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT, - &cm_id_priv->av.port->cm_dev->ca_guid, - sizeof cm_id_priv->av.port->cm_dev->ca_guid, + &cm_id_priv->id.device->node_guid, + sizeof cm_id_priv->id.device->node_guid, NULL, 0); break; case IB_CM_REQ_RCVD: @@ -883,7 +882,7 @@ static void cm_format_req(struct cm_req_msg *req_msg, req_msg->local_comm_id = cm_id_priv->id.local_id; req_msg->service_id = param->service_id; - req_msg->local_ca_guid = cm_id_priv->av.port->cm_dev->ca_guid; + req_msg->local_ca_guid = cm_id_priv->id.device->node_guid; cm_req_set_local_qpn(req_msg, cpu_to_be32(param->qp_num)); cm_req_set_resp_res(req_msg, param->responder_resources); cm_req_set_init_depth(req_msg, param->initiator_depth); @@ -1442,7 +1441,7 @@ static void cm_format_rep(struct cm_rep_msg *rep_msg, cm_rep_set_flow_ctrl(rep_msg, param->flow_control); cm_rep_set_rnr_retry_count(rep_msg, param->rnr_retry_count); cm_rep_set_srq(rep_msg, param->srq); - rep_msg->local_ca_guid = cm_id_priv->av.port->cm_dev->ca_guid; + rep_msg->local_ca_guid = cm_id_priv->id.device->node_guid; if (param->private_data && param->private_data_len) memcpy(rep_msg->private_data, param->private_data, @@ -3385,7 +3384,6 @@ static void cm_add_one(struct ib_device *device) return; cm_dev->device = device; - cm_dev->ca_guid = device->node_guid; set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask); for (i = 1; i <= device->phys_port_cnt; i++) { diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index f8d69b3fa30..fde92ce4515 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -77,7 +77,6 @@ static int next_port; struct cma_device { struct list_head list; struct ib_device *device; - __be64 node_guid; struct completion comp; atomic_t refcount; struct list_head id_list; @@ -1492,11 +1491,13 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms, ib_addr_get_dgid(addr, &path_rec.dgid); path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr)); path_rec.numb_path = 1; + path_rec.reversible = 1; id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device, id_priv->id.port_num, &path_rec, IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | - IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH, + IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH | + IB_SA_PATH_REC_REVERSIBLE, timeout_ms, GFP_KERNEL, cma_query_handler, work, &id_priv->query); @@ -1820,7 +1821,7 @@ static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, struct rdma_bind_list *bind_list; int port, ret; - bind_list = kmalloc(sizeof *bind_list, GFP_KERNEL); + bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL); if (!bind_list) return -ENOMEM; @@ -2672,7 +2673,6 @@ static void cma_add_one(struct ib_device *device) return; cma_dev->device = device; - cma_dev->node_guid = device->node_guid; init_completion(&cma_dev->comp); atomic_set(&cma_dev->refcount, 1); diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index b516b93b855..c859134c1da 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -266,7 +266,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id, mutex_lock(&ctx->file->mut); if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) { if (!ctx->backlog) { - ret = -EDQUOT; + ret = -ENOMEM; kfree(uevent); goto out; } diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index df1efbc1088..4fd75afa6a3 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -622,8 +622,10 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, obj->umem.virt_base = cmd.hca_va; pd = idr_read_pd(cmd.pd_handle, file->ucontext); - if (!pd) + if (!pd) { + ret = -EINVAL; goto err_release; + } mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata); if (IS_ERR(mr)) { diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 8b5dd3649bb..ccdf93d30b0 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -167,7 +167,7 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, struct ib_wc *wc, ah_attr->grh.sgid_index = (u8) gid_index; flow_class = be32_to_cpu(grh->version_tclass_flow); ah_attr->grh.flow_label = flow_class & 0xFFFFF; - ah_attr->grh.hop_limit = grh->hop_limit; + ah_attr->grh.hop_limit = 0xFF; ah_attr->grh.traffic_class = (flow_class >> 20) & 0xFF; } return 0; diff --git a/drivers/infiniband/hw/cxgb3/Makefile b/drivers/infiniband/hw/cxgb3/Makefile index 0e110f32f12..36b98989b15 100644 --- a/drivers/infiniband/hw/cxgb3/Makefile +++ b/drivers/infiniband/hw/cxgb3/Makefile @@ -8,5 +8,4 @@ iw_cxgb3-y := iwch_cm.o iwch_ev.o iwch_cq.o iwch_qp.o iwch_mem.o \ ifdef CONFIG_INFINIBAND_CXGB3_DEBUG EXTRA_CFLAGS += -DDEBUG -iw_cxgb3-y += cxio_dbg.o endif diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 114ac3b775d..818cf1aee8c 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -36,6 +36,7 @@ #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/pci.h> +#include <linux/dma-mapping.h> #include "cxio_resource.h" #include "cxio_hal.h" @@ -45,7 +46,7 @@ static LIST_HEAD(rdev_list); static cxio_hal_ev_callback_func_t cxio_ev_cb = NULL; -static inline struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name) +static struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name) { struct cxio_rdev *rdev; @@ -55,8 +56,7 @@ static inline struct cxio_rdev *cxio_hal_find_rdev_by_name(char *dev_name) return NULL; } -static inline struct cxio_rdev *cxio_hal_find_rdev_by_t3cdev(struct t3cdev - *tdev) +static struct cxio_rdev *cxio_hal_find_rdev_by_t3cdev(struct t3cdev *tdev) { struct cxio_rdev *rdev; @@ -118,7 +118,7 @@ int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq, return 0; } -static inline int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid) +static int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid) { struct rdma_cq_setup setup; setup.id = cqid; @@ -130,7 +130,7 @@ static inline int cxio_hal_clear_cq_ctx(struct cxio_rdev *rdev_p, u32 cqid) return (rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_CQ_SETUP, &setup)); } -int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid) +static int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid) { u64 sge_cmd; struct t3_modify_qp_wr *wqe; @@ -425,7 +425,7 @@ void cxio_flush_hw_cq(struct t3_cq *cq) } } -static inline int cqe_completes_wr(struct t3_cqe *cqe, struct t3_wq *wq) +static int cqe_completes_wr(struct t3_cqe *cqe, struct t3_wq *wq) { if (CQE_OPCODE(*cqe) == T3_TERMINATE) return 0; @@ -760,17 +760,6 @@ ret: return err; } -/* IN : stag key, pdid, pbl_size - * Out: stag index, actaul pbl_size, and pbl_addr allocated. - */ -int cxio_allocate_stag(struct cxio_rdev *rdev_p, u32 * stag, u32 pdid, - enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr) -{ - *stag = T3_STAG_UNSET; - return (__cxio_tpt_op(rdev_p, 0, stag, 0, pdid, TPT_NON_SHARED_MR, - perm, 0, 0ULL, 0, 0, NULL, pbl_size, pbl_addr)); -} - int cxio_register_phys_mem(struct cxio_rdev *rdev_p, u32 *stag, u32 pdid, enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len, u8 page_size, __be64 *pbl, u32 *pbl_size, @@ -1029,7 +1018,7 @@ void __exit cxio_hal_exit(void) cxio_hal_destroy_rhdl_resource(); } -static inline void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq) +static void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq) { struct t3_swsq *sqp; __u32 ptr = wq->sq_rptr; @@ -1058,9 +1047,8 @@ static inline void flush_completed_wrs(struct t3_wq *wq, struct t3_cq *cq) break; } -static inline void create_read_req_cqe(struct t3_wq *wq, - struct t3_cqe *hw_cqe, - struct t3_cqe *read_cqe) +static void create_read_req_cqe(struct t3_wq *wq, struct t3_cqe *hw_cqe, + struct t3_cqe *read_cqe) { read_cqe->u.scqe.wrid_hi = wq->oldest_read->sq_wptr; read_cqe->len = wq->oldest_read->read_len; @@ -1073,7 +1061,7 @@ static inline void create_read_req_cqe(struct t3_wq *wq, /* * Return a ptr to the next read wr in the SWSQ or NULL. */ -static inline void advance_oldest_read(struct t3_wq *wq) +static void advance_oldest_read(struct t3_wq *wq) { u32 rptr = wq->oldest_read - wq->sq + 1; diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h index 8ab04a7c6f6..99543d63470 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.h +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -143,7 +143,6 @@ int cxio_rdev_open(struct cxio_rdev *rdev); void cxio_rdev_close(struct cxio_rdev *rdev); int cxio_hal_cq_op(struct cxio_rdev *rdev, struct t3_cq *cq, enum t3_cq_opcode op, u32 credit); -int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev, u32 qpid); int cxio_create_cq(struct cxio_rdev *rdev, struct t3_cq *cq); int cxio_destroy_cq(struct cxio_rdev *rdev, struct t3_cq *cq); int cxio_resize_cq(struct cxio_rdev *rdev, struct t3_cq *cq); @@ -154,8 +153,6 @@ int cxio_create_qp(struct cxio_rdev *rdev, u32 kernel_domain, struct t3_wq *wq, int cxio_destroy_qp(struct cxio_rdev *rdev, struct t3_wq *wq, struct cxio_ucontext *uctx); int cxio_peek_cq(struct t3_wq *wr, struct t3_cq *cq, int opcode); -int cxio_allocate_stag(struct cxio_rdev *rdev, u32 * stag, u32 pdid, - enum tpt_mem_perm perm, u32 * pbl_size, u32 * pbl_addr); int cxio_register_phys_mem(struct cxio_rdev *rdev, u32 * stag, u32 pdid, enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len, u8 page_size, __be64 *pbl, u32 *pbl_size, @@ -171,8 +168,6 @@ int cxio_deallocate_window(struct cxio_rdev *rdev, u32 stag); int cxio_rdma_init(struct cxio_rdev *rdev, struct t3_rdma_init_attr *attr); void cxio_register_ev_cb(cxio_hal_ev_callback_func_t ev_cb); void cxio_unregister_ev_cb(cxio_hal_ev_callback_func_t ev_cb); -u32 cxio_hal_get_rhdl(void); -void cxio_hal_put_rhdl(u32 rhdl); u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp); void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid); int __init cxio_hal_init(void); diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c index 65bf577311a..d3095ae5bc2 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_resource.c +++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c @@ -179,7 +179,7 @@ tpt_err: /* * returns 0 if no resource available */ -static inline u32 cxio_hal_get_resource(struct kfifo *fifo) +static u32 cxio_hal_get_resource(struct kfifo *fifo) { u32 entry; if (kfifo_get(fifo, (unsigned char *) &entry, sizeof(u32))) @@ -188,21 +188,11 @@ static inline u32 cxio_hal_get_resource(struct kfifo *fifo) return 0; /* fifo emptry */ } -static inline void cxio_hal_put_resource(struct kfifo *fifo, u32 entry) +static void cxio_hal_put_resource(struct kfifo *fifo, u32 entry) { BUG_ON(kfifo_put(fifo, (unsigned char *) &entry, sizeof(u32)) == 0); } -u32 cxio_hal_get_rhdl(void) -{ - return cxio_hal_get_resource(rhdl_fifo); -} - -void cxio_hal_put_rhdl(u32 rhdl) -{ - cxio_hal_put_resource(rhdl_fifo, rhdl); -} - u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp) { return cxio_hal_get_resource(rscp->tpt_fifo); diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index e5442e34b78..d0ed1d35ca3 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -209,8 +209,7 @@ static enum iwch_ep_state state_read(struct iwch_ep_common *epc) return state; } -static inline void __state_set(struct iwch_ep_common *epc, - enum iwch_ep_state new) +static void __state_set(struct iwch_ep_common *epc, enum iwch_ep_state new) { epc->state = new; } @@ -306,8 +305,7 @@ static int status2errno(int status) */ static struct sk_buff *get_skb(struct sk_buff *skb, int len, gfp_t gfp) { - if (skb) { - BUG_ON(skb_cloned(skb)); + if (skb && !skb_is_nonlinear(skb) && !skb_cloned(skb)) { skb_trim(skb, 0); skb_get(skb); } else { @@ -1416,6 +1414,7 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) wake_up(&ep->com.waitq); break; case FPDU_MODE: + start_ep_timer(ep); __state_set(&ep->com, CLOSING); attrs.next_state = IWCH_QP_STATE_CLOSING; iwch_modify_qp(ep->com.qp->rhp, ep->com.qp, @@ -1426,7 +1425,6 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) disconnect = 0; break; case CLOSING: - start_ep_timer(ep); __state_set(&ep->com, MORIBUND); disconnect = 0; break; @@ -1459,7 +1457,7 @@ static int peer_close(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) /* * Returns whether an ABORT_REQ_RSS message is a negative advice. */ -static inline int is_neg_adv_abort(unsigned int status) +static int is_neg_adv_abort(unsigned int status) { return status == CPL_ERR_RTX_NEG_ADVICE || status == CPL_ERR_PERSIST_NEG_ADVICE; @@ -1488,8 +1486,10 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) case CONNECTING: break; case MPA_REQ_WAIT: + stop_ep_timer(ep); break; case MPA_REQ_SENT: + stop_ep_timer(ep); connect_reply_upcall(ep, -ECONNRESET); break; case MPA_REP_SENT: @@ -1508,9 +1508,10 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) get_ep(&ep->com); break; case MORIBUND: + case CLOSING: stop_ep_timer(ep); + /*FALLTHROUGH*/ case FPDU_MODE: - case CLOSING: if (ep->com.cm_id && ep->com.qp) { attrs.next_state = IWCH_QP_STATE_ERROR; ret = iwch_modify_qp(ep->com.qp->rhp, @@ -1571,7 +1572,6 @@ static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) spin_lock_irqsave(&ep->com.lock, flags); switch (ep->com.state) { case CLOSING: - start_ep_timer(ep); __state_set(&ep->com, MORIBUND); break; case MORIBUND: @@ -1587,6 +1587,8 @@ static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) __state_set(&ep->com, DEAD); release = 1; break; + case ABORTING: + break; case DEAD: default: BUG_ON(1); @@ -1635,6 +1637,7 @@ static int ec_status(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) printk(KERN_ERR MOD "%s BAD CLOSE - Aborting tid %u\n", __FUNCTION__, ep->hwtid); + stop_ep_timer(ep); attrs.next_state = IWCH_QP_STATE_ERROR; iwch_modify_qp(ep->com.qp->rhp, ep->com.qp, IWCH_QP_ATTR_NEXT_STATE, @@ -1659,6 +1662,7 @@ static void ep_timeout(unsigned long arg) break; case MPA_REQ_WAIT: break; + case CLOSING: case MORIBUND: if (ep->com.cm_id && ep->com.qp) { attrs.next_state = IWCH_QP_STATE_ERROR; @@ -1687,12 +1691,11 @@ int iwch_reject_cr(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) return -ECONNRESET; } BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD); - state_set(&ep->com, CLOSING); if (mpa_rev == 0) abort_connection(ep, NULL, GFP_KERNEL); else { err = send_mpa_reject(ep, pdata, pdata_len); - err = send_halfclose(ep, GFP_KERNEL); + err = iwch_ep_disconnect(ep, 0, GFP_KERNEL); } return 0; } @@ -1957,11 +1960,11 @@ int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp) case MPA_REQ_RCVD: case MPA_REP_SENT: case FPDU_MODE: + start_ep_timer(ep); ep->com.state = CLOSING; close = 1; break; case CLOSING: - start_ep_timer(ep); ep->com.state = MORIBUND; close = 1; break; diff --git a/drivers/infiniband/hw/cxgb3/iwch_ev.c b/drivers/infiniband/hw/cxgb3/iwch_ev.c index 54362afbf72..b40676662a8 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_ev.c +++ b/drivers/infiniband/hw/cxgb3/iwch_ev.c @@ -47,12 +47,6 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp, struct iwch_qp_attributes attrs; struct iwch_qp *qhp; - printk(KERN_ERR "%s - AE qpid 0x%x opcode %d status 0x%x " - "type %d wrid.hi 0x%x wrid.lo 0x%x \n", __FUNCTION__, - CQE_QPID(rsp_msg->cqe), CQE_OPCODE(rsp_msg->cqe), - CQE_STATUS(rsp_msg->cqe), CQE_TYPE(rsp_msg->cqe), - CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe)); - spin_lock(&rnicp->lock); qhp = get_qhp(rnicp, CQE_QPID(rsp_msg->cqe)); @@ -73,6 +67,12 @@ static void post_qp_event(struct iwch_dev *rnicp, struct iwch_cq *chp, return; } + printk(KERN_ERR "%s - AE qpid 0x%x opcode %d status 0x%x " + "type %d wrid.hi 0x%x wrid.lo 0x%x \n", __FUNCTION__, + CQE_QPID(rsp_msg->cqe), CQE_OPCODE(rsp_msg->cqe), + CQE_STATUS(rsp_msg->cqe), CQE_TYPE(rsp_msg->cqe), + CQE_WRID_HI(rsp_msg->cqe), CQE_WRID_LOW(rsp_msg->cqe)); + atomic_inc(&qhp->refcnt); spin_unlock(&rnicp->lock); diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 2aef122f995..f2774ae906b 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -331,6 +331,7 @@ static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) int ret = 0; struct iwch_mm_entry *mm; struct iwch_ucontext *ucontext; + u64 addr; PDBG("%s pgoff 0x%lx key 0x%x len %d\n", __FUNCTION__, vma->vm_pgoff, key, len); @@ -345,10 +346,11 @@ static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) mm = remove_mmap(ucontext, key, len); if (!mm) return -EINVAL; + addr = mm->addr; kfree(mm); - if ((mm->addr >= rdev_p->rnic_info.udbell_physbase) && - (mm->addr < (rdev_p->rnic_info.udbell_physbase + + if ((addr >= rdev_p->rnic_info.udbell_physbase) && + (addr < (rdev_p->rnic_info.udbell_physbase + rdev_p->rnic_info.udbell_len))) { /* @@ -362,7 +364,7 @@ static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND; vma->vm_flags &= ~VM_MAYREAD; ret = io_remap_pfn_range(vma, vma->vm_start, - mm->addr >> PAGE_SHIFT, + addr >> PAGE_SHIFT, len, vma->vm_page_prot); } else { @@ -370,7 +372,7 @@ static int iwch_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) * Map WQ or CQ contig dma memory... */ ret = remap_pfn_range(vma, vma->vm_start, - mm->addr >> PAGE_SHIFT, + addr >> PAGE_SHIFT, len, vma->vm_page_prot); } @@ -463,9 +465,6 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd, php = to_iwch_pd(pd); rhp = php->rhp; - acc = iwch_convert_access(acc); - - mhp = kzalloc(sizeof(*mhp), GFP_KERNEL); if (!mhp) return ERR_PTR(-ENOMEM); @@ -491,12 +490,7 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd, mhp->attr.pdid = php->pdid; mhp->attr.zbva = 0; - /* NOTE: TPT perms are backwards from BIND WR perms! */ - mhp->attr.perms = (acc & 0x1) << 3; - mhp->attr.perms |= (acc & 0x2) << 1; - mhp->attr.perms |= (acc & 0x4) >> 1; - mhp->attr.perms |= (acc & 0x8) >> 3; - + mhp->attr.perms = iwch_ib_to_tpt_access(acc); mhp->attr.va_fbo = *iova_start; mhp->attr.page_size = shift - 12; @@ -525,7 +519,6 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr, struct iwch_mr mh, *mhp; struct iwch_pd *php; struct iwch_dev *rhp; - int new_acc; __be64 *page_list = NULL; int shift = 0; u64 total_size; @@ -546,14 +539,12 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr, if (rhp != php->rhp) return -EINVAL; - new_acc = mhp->attr.perms; - memcpy(&mh, mhp, sizeof *mhp); if (mr_rereg_mask & IB_MR_REREG_PD) php = to_iwch_pd(pd); if (mr_rereg_mask & IB_MR_REREG_ACCESS) - mh.attr.perms = iwch_convert_access(acc); + mh.attr.perms = iwch_ib_to_tpt_access(acc); if (mr_rereg_mask & IB_MR_REREG_TRANS) ret = build_phys_page_list(buffer_list, num_phys_buf, iova_start, @@ -568,7 +559,7 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr, if (mr_rereg_mask & IB_MR_REREG_PD) mhp->attr.pdid = php->pdid; if (mr_rereg_mask & IB_MR_REREG_ACCESS) - mhp->attr.perms = acc; + mhp->attr.perms = iwch_ib_to_tpt_access(acc); if (mr_rereg_mask & IB_MR_REREG_TRANS) { mhp->attr.zbva = 0; mhp->attr.va_fbo = *iova_start; @@ -613,8 +604,6 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, goto err; } - acc = iwch_convert_access(acc); - i = n = 0; list_for_each_entry(chunk, ®ion->chunk_list, list) @@ -630,10 +619,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, struct ib_umem *region, mhp->rhp = rhp; mhp->attr.pdid = php->pdid; mhp->attr.zbva = 0; - mhp->attr.perms = (acc & 0x1) << 3; - mhp->attr.perms |= (acc & 0x2) << 1; - mhp->attr.perms |= (acc & 0x4) >> 1; - mhp->attr.perms |= (acc & 0x8) >> 3; + mhp->attr.perms = iwch_ib_to_tpt_access(acc); mhp->attr.va_fbo = region->virt_base; mhp->attr.page_size = shift - 12; mhp->attr.len = (u32) region->length; @@ -736,10 +722,8 @@ static int iwch_destroy_qp(struct ib_qp *ib_qp) qhp = to_iwch_qp(ib_qp); rhp = qhp->rhp; - if (qhp->attr.state == IWCH_QP_STATE_RTS) { - attrs.next_state = IWCH_QP_STATE_ERROR; - iwch_modify_qp(rhp, qhp, IWCH_QP_ATTR_NEXT_STATE, &attrs, 0); - } + attrs.next_state = IWCH_QP_STATE_ERROR; + iwch_modify_qp(rhp, qhp, IWCH_QP_ATTR_NEXT_STATE, &attrs, 0); wait_event(qhp->wait, !qhp->ep); remove_handle(rhp, &rhp->qpidr, qhp->wq.qpid); @@ -948,7 +932,7 @@ void iwch_qp_rem_ref(struct ib_qp *qp) wake_up(&(to_iwch_qp(qp)->wait)); } -struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn) +static struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn) { PDBG("%s ib_dev %p qpn 0x%x\n", __FUNCTION__, dev, qpn); return (struct ib_qp *)get_qhp(to_iwch_dev(dev), qpn); diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index 2af3e93b607..93bcc56756b 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h @@ -178,7 +178,6 @@ static inline struct iwch_qp *to_iwch_qp(struct ib_qp *ibqp) void iwch_qp_add_ref(struct ib_qp *qp); void iwch_qp_rem_ref(struct ib_qp *qp); -struct ib_qp *iwch_get_qp(struct ib_device *dev, int qpn); struct iwch_ucontext { struct ib_ucontext ibucontext; @@ -287,27 +286,20 @@ static inline int iwch_convert_state(enum ib_qp_state ib_state) } } -enum iwch_mem_perms { - IWCH_MEM_ACCESS_LOCAL_READ = 1 << 0, - IWCH_MEM_ACCESS_LOCAL_WRITE = 1 << 1, - IWCH_MEM_ACCESS_REMOTE_READ = 1 << 2, - IWCH_MEM_ACCESS_REMOTE_WRITE = 1 << 3, - IWCH_MEM_ACCESS_ATOMICS = 1 << 4, - IWCH_MEM_ACCESS_BINDING = 1 << 5, - IWCH_MEM_ACCESS_LOCAL = - (IWCH_MEM_ACCESS_LOCAL_READ | IWCH_MEM_ACCESS_LOCAL_WRITE), - IWCH_MEM_ACCESS_REMOTE = - (IWCH_MEM_ACCESS_REMOTE_WRITE | IWCH_MEM_ACCESS_REMOTE_READ) - /* cannot go beyond 1 << 31 */ -} __attribute__ ((packed)); - -static inline u32 iwch_convert_access(int acc) +static inline u32 iwch_ib_to_tpt_access(int acc) { - return (acc & IB_ACCESS_REMOTE_WRITE ? IWCH_MEM_ACCESS_REMOTE_WRITE : 0) - | (acc & IB_ACCESS_REMOTE_READ ? IWCH_MEM_ACCESS_REMOTE_READ : 0) | - (acc & IB_ACCESS_LOCAL_WRITE ? IWCH_MEM_ACCESS_LOCAL_WRITE : 0) | - (acc & IB_ACCESS_MW_BIND ? IWCH_MEM_ACCESS_BINDING : 0) | - IWCH_MEM_ACCESS_LOCAL_READ; + return (acc & IB_ACCESS_REMOTE_WRITE ? TPT_REMOTE_WRITE : 0) | + (acc & IB_ACCESS_REMOTE_READ ? TPT_REMOTE_READ : 0) | + (acc & IB_ACCESS_LOCAL_WRITE ? TPT_LOCAL_WRITE : 0) | + TPT_LOCAL_READ; +} + +static inline u32 iwch_ib_to_mwbind_access(int acc) +{ + return (acc & IB_ACCESS_REMOTE_WRITE ? T3_MEM_ACCESS_REM_WRITE : 0) | + (acc & IB_ACCESS_REMOTE_READ ? T3_MEM_ACCESS_REM_READ : 0) | + (acc & IB_ACCESS_LOCAL_WRITE ? T3_MEM_ACCESS_LOCAL_WRITE : 0) | + T3_MEM_ACCESS_LOCAL_READ; } enum iwch_mmid_state { diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 4dda2f6da2d..0a472c9b44d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -36,8 +36,8 @@ #define NO_SUPPORT -1 -static inline int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr, - u8 * flit_cnt) +static int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr, + u8 * flit_cnt) { int i; u32 plen; @@ -96,8 +96,8 @@ static inline int iwch_build_rdma_send(union t3_wr *wqe, struct ib_send_wr *wr, return 0; } -static inline int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr, - u8 *flit_cnt) +static int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr, + u8 *flit_cnt) { int i; u32 plen; @@ -137,8 +137,8 @@ static inline int iwch_build_rdma_write(union t3_wr *wqe, struct ib_send_wr *wr, return 0; } -static inline int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr, - u8 *flit_cnt) +static int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr, + u8 *flit_cnt) { if (wr->num_sge > 1) return -EINVAL; @@ -158,9 +158,8 @@ static inline int iwch_build_rdma_read(union t3_wr *wqe, struct ib_send_wr *wr, /* * TBD: this is going to be moved to firmware. Missing pdid/qpid check for now. */ -static inline int iwch_sgl2pbl_map(struct iwch_dev *rhp, - struct ib_sge *sg_list, u32 num_sgle, - u32 * pbl_addr, u8 * page_size) +static int iwch_sgl2pbl_map(struct iwch_dev *rhp, struct ib_sge *sg_list, + u32 num_sgle, u32 * pbl_addr, u8 * page_size) { int i; struct iwch_mr *mhp; @@ -206,9 +205,8 @@ static inline int iwch_sgl2pbl_map(struct iwch_dev *rhp, return 0; } -static inline int iwch_build_rdma_recv(struct iwch_dev *rhp, - union t3_wr *wqe, - struct ib_recv_wr *wr) +static int iwch_build_rdma_recv(struct iwch_dev *rhp, union t3_wr *wqe, + struct ib_recv_wr *wr) { int i, err = 0; u32 pbl_addr[4]; @@ -441,7 +439,7 @@ int iwch_bind_mw(struct ib_qp *qp, wqe->bind.type = T3_VA_BASED_TO; /* TBD: check perms */ - wqe->bind.perms = iwch_convert_access(mw_bind->mw_access_flags); + wqe->bind.perms = iwch_ib_to_mwbind_access(mw_bind->mw_access_flags); wqe->bind.mr_stag = cpu_to_be32(mw_bind->mr->lkey); wqe->bind.mw_stag = cpu_to_be32(mw->rkey); wqe->bind.mw_len = cpu_to_be32(mw_bind->length); @@ -473,8 +471,7 @@ int iwch_bind_mw(struct ib_qp *qp, return err; } -static inline void build_term_codes(int t3err, u8 *layer_type, u8 *ecode, - int tagged) +static void build_term_codes(int t3err, u8 *layer_type, u8 *ecode, int tagged) { switch (t3err) { case TPT_ERR_STAG: @@ -672,7 +669,7 @@ static void __flush_qp(struct iwch_qp *qhp, unsigned long *flag) spin_lock_irqsave(&qhp->lock, *flag); } -static inline void flush_qp(struct iwch_qp *qhp, unsigned long *flag) +static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) { if (t3b_device(qhp->rhp)) cxio_set_wq_in_error(&qhp->wq); @@ -684,7 +681,7 @@ static inline void flush_qp(struct iwch_qp *qhp, unsigned long *flag) /* * Return non zero if at least one RECV was pre-posted. */ -static inline int rqes_posted(struct iwch_qp *qhp) +static int rqes_posted(struct iwch_qp *qhp) { return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV; } diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 40404c9e281..82ded44c6ce 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -52,6 +52,8 @@ struct ehca_mw; struct ehca_pd; struct ehca_av; +#include <linux/wait.h> + #include <rdma/ib_verbs.h> #include <rdma/ib_user_verbs.h> @@ -153,7 +155,9 @@ struct ehca_cq { spinlock_t cb_lock; struct hlist_head qp_hashtab[QP_HASHTAB_LEN]; struct list_head entry; - u32 nr_callbacks; + u32 nr_callbacks; /* #events assigned to cpu by scaling code */ + u32 nr_events; /* #events seen */ + wait_queue_head_t wait_completion; spinlock_t task_lock; u32 ownpid; /* mmap counter for resources mapped into user space */ diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index 6ebfa27e4e1..e2cdc1a16fe 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -146,6 +146,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, spin_lock_init(&my_cq->spinlock); spin_lock_init(&my_cq->cb_lock); spin_lock_init(&my_cq->task_lock); + init_waitqueue_head(&my_cq->wait_completion); my_cq->ownpid = current->tgid; cq = &my_cq->ib_cq; @@ -302,6 +303,16 @@ create_cq_exit1: return cq; } +static int get_cq_nr_events(struct ehca_cq *my_cq) +{ + int ret; + unsigned long flags; + spin_lock_irqsave(&ehca_cq_idr_lock, flags); + ret = my_cq->nr_events; + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + return ret; +} + int ehca_destroy_cq(struct ib_cq *cq) { u64 h_ret; @@ -329,10 +340,11 @@ int ehca_destroy_cq(struct ib_cq *cq) } spin_lock_irqsave(&ehca_cq_idr_lock, flags); - while (my_cq->nr_callbacks) { + while (my_cq->nr_events) { spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); - yield(); + wait_event(my_cq->wait_completion, !get_cq_nr_events(my_cq)); spin_lock_irqsave(&ehca_cq_idr_lock, flags); + /* recheck nr_events to assure no cqe has just arrived */ } idr_remove(&ehca_cq_idr, my_cq->token); diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c index 3ec53c687d0..20f36bf8b2b 100644 --- a/drivers/infiniband/hw/ehca/ehca_irq.c +++ b/drivers/infiniband/hw/ehca/ehca_irq.c @@ -404,10 +404,11 @@ static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe) u32 token; unsigned long flags; struct ehca_cq *cq; + eqe_value = eqe->entry; ehca_dbg(&shca->ib_device, "eqe_value=%lx", eqe_value); if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) { - ehca_dbg(&shca->ib_device, "... completion event"); + ehca_dbg(&shca->ib_device, "Got completion event"); token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value); spin_lock_irqsave(&ehca_cq_idr_lock, flags); cq = idr_find(&ehca_cq_idr, token); @@ -419,16 +420,20 @@ static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe) return; } reset_eq_pending(cq); - if (ehca_scaling_code) { + cq->nr_events++; + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + if (ehca_scaling_code) queue_comp_task(cq); - spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); - } else { - spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + else { comp_event_callback(cq); + spin_lock_irqsave(&ehca_cq_idr_lock, flags); + cq->nr_events--; + if (!cq->nr_events) + wake_up(&cq->wait_completion); + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); } } else { - ehca_dbg(&shca->ib_device, - "Got non completion event"); + ehca_dbg(&shca->ib_device, "Got non completion event"); parse_identifier(shca, eqe_value); } } @@ -478,6 +483,7 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq) "token=%x", token); continue; } + eqe_cache[eqe_cnt].cq->nr_events++; spin_unlock(&ehca_cq_idr_lock); } else eqe_cache[eqe_cnt].cq = NULL; @@ -504,12 +510,18 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq) /* call completion handler for cached eqes */ for (i = 0; i < eqe_cnt; i++) if (eq->eqe_cache[i].cq) { - if (ehca_scaling_code) { - spin_lock(&ehca_cq_idr_lock); + if (ehca_scaling_code) queue_comp_task(eq->eqe_cache[i].cq); - spin_unlock(&ehca_cq_idr_lock); - } else - comp_event_callback(eq->eqe_cache[i].cq); + else { + struct ehca_cq *cq = eq->eqe_cache[i].cq; + comp_event_callback(cq); + spin_lock_irqsave(&ehca_cq_idr_lock, flags); + cq->nr_events--; + if (!cq->nr_events) + wake_up(&cq->wait_completion); + spin_unlock_irqrestore(&ehca_cq_idr_lock, + flags); + } } else { ehca_dbg(&shca->ib_device, "Got non completion event"); parse_identifier(shca, eq->eqe_cache[i].eqe->entry); @@ -523,7 +535,6 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq) if (!eqe) break; process_eqe(shca, eqe); - eqe_cnt++; } while (1); unlock_irq_spinlock: @@ -567,8 +578,7 @@ static void __queue_comp_task(struct ehca_cq *__cq, list_add_tail(&__cq->entry, &cct->cq_list); cct->cq_jobs++; wake_up(&cct->wait_queue); - } - else + } else __cq->nr_callbacks++; spin_unlock(&__cq->task_lock); @@ -577,18 +587,21 @@ static void __queue_comp_task(struct ehca_cq *__cq, static void queue_comp_task(struct ehca_cq *__cq) { - int cpu; int cpu_id; struct ehca_cpu_comp_task *cct; + int cq_jobs; + unsigned long flags; - cpu = get_cpu(); cpu_id = find_next_online_cpu(pool); BUG_ON(!cpu_online(cpu_id)); cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); BUG_ON(!cct); - if (cct->cq_jobs > 0) { + spin_lock_irqsave(&cct->task_lock, flags); + cq_jobs = cct->cq_jobs; + spin_unlock_irqrestore(&cct->task_lock, flags); + if (cq_jobs > 0) { cpu_id = find_next_online_cpu(pool); cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id); BUG_ON(!cct); @@ -608,11 +621,17 @@ static void run_comp_task(struct ehca_cpu_comp_task* cct) cq = list_entry(cct->cq_list.next, struct ehca_cq, entry); spin_unlock_irqrestore(&cct->task_lock, flags); comp_event_callback(cq); - spin_lock_irqsave(&cct->task_lock, flags); + spin_lock_irqsave(&ehca_cq_idr_lock, flags); + cq->nr_events--; + if (!cq->nr_events) + wake_up(&cq->wait_completion); + spin_unlock_irqrestore(&ehca_cq_idr_lock, flags); + + spin_lock_irqsave(&cct->task_lock, flags); spin_lock(&cq->task_lock); cq->nr_callbacks--; - if (cq->nr_callbacks == 0) { + if (!cq->nr_callbacks) { list_del_init(cct->cq_list.next); cct->cq_jobs--; } diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index c1835121a82..059da9628bb 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -52,7 +52,7 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>"); MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver"); -MODULE_VERSION("SVNEHCA_0021"); +MODULE_VERSION("SVNEHCA_0022"); int ehca_open_aqp1 = 0; int ehca_debug_level = 0; @@ -810,7 +810,7 @@ int __init ehca_module_init(void) int ret; printk(KERN_INFO "eHCA Infiniband Device Driver " - "(Rel.: SVNEHCA_0021)\n"); + "(Rel.: SVNEHCA_0022)\n"); idr_init(&ehca_qp_idr); idr_init(&ehca_cq_idr); spin_lock_init(&ehca_qp_idr_lock); diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 6037dd3f87d..8e4846b5c64 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -310,8 +310,9 @@ int mthca_write_mtt_size(struct mthca_dev *dev) return mthca_is_memfree(dev) ? (PAGE_SIZE / sizeof (u64)) : 0x7ffffff; } -void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt, - int start_index, u64 *buffer_list, int list_len) +static void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, + struct mthca_mtt *mtt, int start_index, + u64 *buffer_list, int list_len) { u64 __iomem *mtts; int i; @@ -323,8 +324,9 @@ void mthca_tavor_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt, mtts + i); } -void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, struct mthca_mtt *mtt, - int start_index, u64 *buffer_list, int list_len) +static void mthca_arbel_write_mtt_seg(struct mthca_dev *dev, + struct mthca_mtt *mtt, int start_index, + u64 *buffer_list, int list_len) { __be64 *mtts; dma_addr_t dma_handle; diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index 71dc84bd425..1c6b63aca26 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -1088,21 +1088,21 @@ static void mthca_unmap_memfree(struct mthca_dev *dev, static int mthca_alloc_memfree(struct mthca_dev *dev, struct mthca_qp *qp) { - int ret = 0; - if (mthca_is_memfree(dev)) { qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ, qp->qpn, &qp->rq.db); if (qp->rq.db_index < 0) - return ret; + return -ENOMEM; qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ, qp->qpn, &qp->sq.db); - if (qp->sq.db_index < 0) + if (qp->sq.db_index < 0) { mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index); + return -ENOMEM; + } } - return ret; + return 0; } static void mthca_free_memfree(struct mthca_dev *dev, diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 2594db2030b..fd558267d1c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -219,7 +219,6 @@ struct ipoib_dev_priv { union ib_gid local_gid; u16 local_lid; - u8 local_rate; unsigned int admin_mtu; unsigned int mcast_mtu; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 4d59682f7d4..3484e8ba24a 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -65,14 +65,14 @@ struct ipoib_cm_id { static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); -static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, +static void ipoib_cm_dma_unmap_rx(struct ipoib_dev_priv *priv, int frags, u64 mapping[IPOIB_CM_RX_SG]) { int i; ib_dma_unmap_single(priv->ca, mapping[0], IPOIB_CM_HEAD_SIZE, DMA_FROM_DEVICE); - for (i = 0; i < IPOIB_CM_RX_SG - 1; ++i) + for (i = 0; i < frags; ++i) ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE); } @@ -90,7 +90,8 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id) ret = ib_post_srq_recv(priv->cm.srq, &priv->cm.rx_wr, &bad_wr); if (unlikely(ret)) { ipoib_warn(priv, "post srq failed for buf %d (%d)\n", id, ret); - ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[id].mapping); + ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, + priv->cm.srq_ring[id].mapping); dev_kfree_skb_any(priv->cm.srq_ring[id].skb); priv->cm.srq_ring[id].skb = NULL; } @@ -98,8 +99,8 @@ static int ipoib_cm_post_receive(struct net_device *dev, int id) return ret; } -static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, - u64 mapping[IPOIB_CM_RX_SG]) +static struct sk_buff *ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, int frags, + u64 mapping[IPOIB_CM_RX_SG]) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct sk_buff *skb; @@ -107,7 +108,7 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, skb = dev_alloc_skb(IPOIB_CM_HEAD_SIZE + 12); if (unlikely(!skb)) - return -ENOMEM; + return NULL; /* * IPoIB adds a 4 byte header. So we need 12 more bytes to align the @@ -119,10 +120,10 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, DMA_FROM_DEVICE); if (unlikely(ib_dma_mapping_error(priv->ca, mapping[0]))) { dev_kfree_skb_any(skb); - return -EIO; + return NULL; } - for (i = 0; i < IPOIB_CM_RX_SG - 1; i++) { + for (i = 0; i < frags; i++) { struct page *page = alloc_page(GFP_ATOMIC); if (!page) @@ -136,7 +137,7 @@ static int ipoib_cm_alloc_rx_skb(struct net_device *dev, int id, } priv->cm.srq_ring[id].skb = skb; - return 0; + return skb; partial_error: @@ -146,7 +147,7 @@ partial_error: ib_dma_unmap_single(priv->ca, mapping[i + 1], PAGE_SIZE, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); - return -ENOMEM; + return NULL; } static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev, @@ -309,7 +310,7 @@ static int ipoib_cm_rx_handler(struct ib_cm_id *cm_id, } /* Adjust length of skb with fragments to match received data */ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space, - unsigned int length) + unsigned int length, struct sk_buff *toskb) { int i, num_frags; unsigned int size; @@ -326,7 +327,7 @@ static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space, if (length == 0) { /* don't need this page */ - __free_page(frag->page); + skb_fill_page_desc(toskb, i, frag->page, 0, PAGE_SIZE); --skb_shinfo(skb)->nr_frags; } else { size = min(length, (unsigned) PAGE_SIZE); @@ -344,10 +345,11 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) { struct ipoib_dev_priv *priv = netdev_priv(dev); unsigned int wr_id = wc->wr_id & ~IPOIB_CM_OP_SRQ; - struct sk_buff *skb; + struct sk_buff *skb, *newskb; struct ipoib_cm_rx *p; unsigned long flags; u64 mapping[IPOIB_CM_RX_SG]; + int frags; ipoib_dbg_data(priv, "cm recv completion: id %d, op %d, status: %d\n", wr_id, wc->opcode, wc->status); @@ -383,7 +385,11 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) } } - if (unlikely(ipoib_cm_alloc_rx_skb(dev, wr_id, mapping))) { + frags = PAGE_ALIGN(wc->byte_len - min(wc->byte_len, + (unsigned)IPOIB_CM_HEAD_SIZE)) / PAGE_SIZE; + + newskb = ipoib_cm_alloc_rx_skb(dev, wr_id, frags, mapping); + if (unlikely(!newskb)) { /* * If we can't allocate a new RX buffer, dump * this packet and reuse the old buffer. @@ -393,13 +399,13 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc) goto repost; } - ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[wr_id].mapping); - memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, sizeof mapping); + ipoib_cm_dma_unmap_rx(priv, frags, priv->cm.srq_ring[wr_id].mapping); + memcpy(priv->cm.srq_ring[wr_id].mapping, mapping, (frags + 1) * sizeof *mapping); ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n", wc->byte_len, wc->slid); - skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len); + skb_put_frags(skb, IPOIB_CM_HEAD_SIZE, wc->byte_len, newskb); skb->protocol = ((struct ipoib_header *) skb->data)->proto; skb->mac.raw = skb->data; @@ -1193,7 +1199,8 @@ int ipoib_cm_dev_init(struct net_device *dev) priv->cm.rx_wr.num_sge = IPOIB_CM_RX_SG; for (i = 0; i < ipoib_recvq_size; ++i) { - if (ipoib_cm_alloc_rx_skb(dev, i, priv->cm.srq_ring[i].mapping)) { + if (!ipoib_cm_alloc_rx_skb(dev, i, IPOIB_CM_RX_SG - 1, + priv->cm.srq_ring[i].mapping)) { ipoib_warn(priv, "failed to allocate receive buffer %d\n", i); ipoib_cm_dev_cleanup(dev); return -ENOMEM; @@ -1228,7 +1235,8 @@ void ipoib_cm_dev_cleanup(struct net_device *dev) return; for (i = 0; i < ipoib_recvq_size; ++i) if (priv->cm.srq_ring[i].skb) { - ipoib_cm_dma_unmap_rx(priv, priv->cm.srq_ring[i].mapping); + ipoib_cm_dma_unmap_rx(priv, IPOIB_CM_RX_SG - 1, + priv->cm.srq_ring[i].mapping); dev_kfree_skb_any(priv->cm.srq_ring[i].skb); priv->cm.srq_ring[i].skb = NULL; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 18d27fd352a..f9dbc6f6814 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -385,7 +385,7 @@ static void path_rec_completion(int status, struct sk_buff *skb; unsigned long flags; - if (pathrec) + if (!status) ipoib_dbg(priv, "PathRec LID 0x%04x for GID " IPOIB_GID_FMT "\n", be16_to_cpu(pathrec->dlid), IPOIB_GID_ARG(pathrec->dgid)); else diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index b303ce6bc21..56c87a81bb6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -407,6 +407,10 @@ static int ipoib_mcast_join_complete(int status, queue_delayed_work(ipoib_workqueue, &priv->mcast_task, 0); mutex_unlock(&mcast_mutex); + + if (mcast == priv->broadcast) + netif_carrier_on(dev); + return 0; } @@ -527,11 +531,9 @@ void ipoib_mcast_join_task(struct work_struct *work) { struct ib_port_attr attr; - if (!ib_query_port(priv->ca, priv->port, &attr)) { - priv->local_lid = attr.lid; - priv->local_rate = attr.active_speed * - ib_width_enum_to_int(attr.active_width); - } else + if (!ib_query_port(priv->ca, priv->port, &attr)) + priv->local_lid = attr.lid; + else ipoib_warn(priv, "ib_query_port failed\n"); } @@ -596,7 +598,6 @@ void ipoib_mcast_join_task(struct work_struct *work) ipoib_dbg_mcast(priv, "successfully joined all multicast groups\n"); clear_bit(IPOIB_MCAST_RUN, &priv->flags); - netif_carrier_on(dev); } int ipoib_mcast_start_thread(struct net_device *dev) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 3cb551b8875..7f3ec205e35 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -259,12 +259,13 @@ void ipoib_event(struct ib_event_handler *handler, struct ipoib_dev_priv *priv = container_of(handler, struct ipoib_dev_priv, event_handler); - if (record->event == IB_EVENT_PORT_ERR || - record->event == IB_EVENT_PKEY_CHANGE || - record->event == IB_EVENT_PORT_ACTIVE || - record->event == IB_EVENT_LID_CHANGE || - record->event == IB_EVENT_SM_CHANGE || - record->event == IB_EVENT_CLIENT_REREGISTER) { + if ((record->event == IB_EVENT_PORT_ERR || + record->event == IB_EVENT_PKEY_CHANGE || + record->event == IB_EVENT_PORT_ACTIVE || + record->event == IB_EVENT_LID_CHANGE || + record->event == IB_EVENT_SM_CHANGE || + record->event == IB_EVENT_CLIENT_REREGISTER) && + record->element.port_num == priv->port) { ipoib_dbg(priv, "Port state change event\n"); queue_work(ipoib_workqueue, &priv->flush_task); } diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 64509689fa6..f17e9c7d4b3 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -215,14 +215,16 @@ config KEYBOARD_AAED2000 module will be called aaed2000_kbd. config KEYBOARD_GPIO - tristate "Buttons on CPU GPIOs (PXA)" - depends on (ARCH_SA1100 || ARCH_PXA || ARCH_S3C2410) + tristate "GPIO Buttons" + depends on GENERIC_GPIO help This driver implements support for buttons connected - directly to GPIO pins of SA1100, PXA or S3C24xx CPUs. + to GPIO pins of various CPUs (and some other chips). Say Y here if your device has buttons connected - directly to GPIO pins of the CPU. + directly to such GPIO pins. Your board-specific + setup logic must also provide a platform device, + with configuration data saying which GPIOs are used. To compile this driver as a module, choose M here: the module will be called gpio-keys. diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index fa03a00b4c6..ccf6df387b6 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -23,11 +23,9 @@ #include <linux/platform_device.h> #include <linux/input.h> #include <linux/irq.h> +#include <linux/gpio_keys.h> #include <asm/gpio.h> -#include <asm/arch/hardware.h> - -#include <asm/hardware/gpio_keys.h> static irqreturn_t gpio_keys_isr(int irq, void *dev_id) { diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index ec195a36e8f..db9cca3b65e 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -553,7 +553,8 @@ static int __devinit i8042_check_aux(void) */ param = 0x5a; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0x5a) { + retval = i8042_command(¶m, I8042_CMD_AUX_LOOP); + if (retval || param != 0x5a) { /* * External connection test - filters out AT-soldered PS/2 i8042's @@ -567,7 +568,12 @@ static int __devinit i8042_check_aux(void) (param && param != 0xfa && param != 0xff)) return -1; - aux_loop_broken = 1; +/* + * If AUX_LOOP completed without error but returned unexpected data + * mark it as broken + */ + if (!retval) + aux_loop_broken = 1; } /* diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig index 8b6c9a431ff..c921d6c522f 100644 --- a/drivers/isdn/capi/Kconfig +++ b/drivers/isdn/capi/Kconfig @@ -2,13 +2,25 @@ # Config.in for the CAPI subsystem # config ISDN_DRV_AVMB1_VERBOSE_REASON - bool "Verbose reason code reporting (kernel size +=7K)" + bool "Verbose reason code reporting" depends on ISDN_CAPI + default y help - If you say Y here, the AVM B1 driver will give verbose reasons for + If you say Y here, the CAPI drivers will give verbose reasons for disconnecting. This will increase the size of the kernel by 7 KB. If unsure, say Y. +config CAPI_TRACE + bool "CAPI trace support" + depends on ISDN_CAPI + default y + help + If you say Y here, the kernelcapi driver can make verbose traces + of CAPI messages. This feature can be enabled/disabled via IOCTL for + every controler (default disabled). + This will increase the size of the kernelcapi module by 20 KB. + If unsure, say Y. + config ISDN_CAPI_MIDDLEWARE bool "CAPI2.0 Middleware support (EXPERIMENTAL)" depends on ISDN_CAPI && EXPERIMENTAL diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index 2a49cea0a22..23b6f7bc16b 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -990,6 +990,7 @@ static void handle_plci(_cmsg * cmsg) capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); capidrv_plci *plcip; isdn_ctrl cmd; + _cdebbuf *cdb; if (!card) { printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", @@ -1122,8 +1123,15 @@ static void handle_plci(_cmsg * cmsg) break; } } - printk(KERN_ERR "capidrv-%d: %s\n", - card->contrnr, capi_cmsg2str(cmsg)); + cdb = capi_cmsg2str(cmsg); + if (cdb) { + printk(KERN_WARNING "capidrv-%d: %s\n", + card->contrnr, cdb->buf); + cdebbuf_free(cdb); + } else + printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n", + card->contrnr, cmsg->InfoNumber); + break; case CAPI_CONNECT_ACTIVE_CONF: /* plci */ @@ -1371,10 +1379,18 @@ static _cmsg s_cmsg; static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) { capi_message2cmsg(&s_cmsg, skb->data); - if (debugmode > 3) - printk(KERN_DEBUG "capidrv_signal: applid=%d %s\n", - ap->applid, capi_cmsg2str(&s_cmsg)); - + if (debugmode > 3) { + _cdebbuf *cdb = capi_cmsg2str(&s_cmsg); + + if (cdb) { + printk(KERN_DEBUG "%s: applid=%d %s\n", __FUNCTION__, + ap->applid, cdb->buf); + cdebbuf_free(cdb); + } else + printk(KERN_DEBUG "%s: applid=%d %s not traced\n", + __FUNCTION__, ap->applid, + capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand)); + } if (s_cmsg.Command == CAPI_DATA_B3 && s_cmsg.Subcommand == CAPI_IND) { handle_data(&s_cmsg, skb); diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c index c1b21552fc0..ad1e2702c2d 100644 --- a/drivers/isdn/capi/capiutil.c +++ b/drivers/isdn/capi/capiutil.c @@ -648,6 +648,9 @@ char *capi_cmd2str(u8 cmd, u8 subcmd) /*-------------------------------------------------------*/ + +#ifdef CONFIG_CAPI_TRACE + /*-------------------------------------------------------*/ static char *pnames[] = @@ -703,44 +706,77 @@ static char *pnames[] = }; -static char buf[8192]; -static char *p = NULL; #include <stdarg.h> /*-------------------------------------------------------*/ -static void bufprint(char *fmt,...) +static _cdebbuf *bufprint(_cdebbuf *cdb, char *fmt,...) { va_list f; + size_t n,r; + + if (!cdb) + return NULL; va_start(f, fmt); - vsprintf(p, fmt, f); + r = cdb->size - cdb->pos; + n = vsnprintf(cdb->p, r, fmt, f); va_end(f); - p += strlen(p); + if (n >= r) { + /* truncated, need bigger buffer */ + size_t ns = 2 * cdb->size; + u_char *nb; + + while ((ns - cdb->pos) <= n) + ns *= 2; + nb = kmalloc(ns, GFP_ATOMIC); + if (!nb) { + cdebbuf_free(cdb); + return NULL; + } + memcpy(nb, cdb->buf, cdb->pos); + kfree(cdb->buf); + nb[cdb->pos] = 0; + cdb->buf = nb; + cdb->p = cdb->buf + cdb->pos; + cdb->size = ns; + va_start(f, fmt); + r = cdb->size - cdb->pos; + n = vsnprintf(cdb->p, r, fmt, f); + va_end(f); + } + cdb->p += n; + cdb->pos += n; + return cdb; } -static void printstructlen(u8 * m, unsigned len) +static _cdebbuf *printstructlen(_cdebbuf *cdb, u8 * m, unsigned len) { unsigned hex = 0; + + if (!cdb) + return NULL; for (; len; len--, m++) if (isalnum(*m) || *m == ' ') { if (hex) - bufprint(">"); - bufprint("%c", *m); + cdb = bufprint(cdb, ">"); + cdb = bufprint(cdb, "%c", *m); hex = 0; } else { if (!hex) - bufprint("<%02x", *m); + cdb = bufprint(cdb, "<%02x", *m); else - bufprint(" %02x", *m); + cdb = bufprint(cdb, " %02x", *m); hex = 1; } if (hex) - bufprint(">"); + cdb = bufprint(cdb, ">"); + return cdb; } -static void printstruct(u8 * m) +static _cdebbuf *printstruct(_cdebbuf *cdb, u8 * m) { unsigned len; + if (m[0] != 0xff) { len = m[0]; m += 1; @@ -748,42 +784,45 @@ static void printstruct(u8 * m) len = ((u16 *) (m + 1))[0]; m += 3; } - printstructlen(m, len); + cdb = printstructlen(cdb, m, len); + return cdb; } /*-------------------------------------------------------*/ #define NAME (pnames[cmsg->par[cmsg->p]]) -static void protocol_message_2_pars(_cmsg * cmsg, int level) +static _cdebbuf *protocol_message_2_pars(_cdebbuf *cdb, _cmsg *cmsg, int level) { for (; TYP != _CEND; cmsg->p++) { int slen = 29 + 3 - level; int i; - bufprint(" "); + if (!cdb) + return NULL; + cdb = bufprint(cdb, " "); for (i = 0; i < level - 1; i++) - bufprint(" "); + cdb = bufprint(cdb, " "); switch (TYP) { case _CBYTE: - bufprint("%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l)); + cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u8 *) (cmsg->m + cmsg->l)); cmsg->l++; break; case _CWORD: - bufprint("%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l)); + cdb = bufprint(cdb, "%-*s = 0x%x\n", slen, NAME, *(u16 *) (cmsg->m + cmsg->l)); cmsg->l += 2; break; case _CDWORD: - bufprint("%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l)); + cdb = bufprint(cdb, "%-*s = 0x%lx\n", slen, NAME, *(u32 *) (cmsg->m + cmsg->l)); cmsg->l += 4; break; case _CSTRUCT: - bufprint("%-*s = ", slen, NAME); + cdb = bufprint(cdb, "%-*s = ", slen, NAME); if (cmsg->m[cmsg->l] == '\0') - bufprint("default"); + cdb = bufprint(cdb, "default"); else - printstruct(cmsg->m + cmsg->l); - bufprint("\n"); + cdb = printstruct(cdb, cmsg->m + cmsg->l); + cdb = bufprint(cdb, "\n"); if (cmsg->m[cmsg->l] != 0xff) cmsg->l += 1 + cmsg->m[cmsg->l]; else @@ -794,61 +833,184 @@ static void protocol_message_2_pars(_cmsg * cmsg, int level) case _CMSTRUCT: /*----- Metastruktur 0 -----*/ if (cmsg->m[cmsg->l] == '\0') { - bufprint("%-*s = default\n", slen, NAME); + cdb = bufprint(cdb, "%-*s = default\n", slen, NAME); cmsg->l++; jumpcstruct(cmsg); } else { char *name = NAME; unsigned _l = cmsg->l; - bufprint("%-*s\n", slen, name); + cdb = bufprint(cdb, "%-*s\n", slen, name); cmsg->l = (cmsg->m + _l)[0] == 255 ? cmsg->l + 3 : cmsg->l + 1; cmsg->p++; - protocol_message_2_pars(cmsg, level + 1); + cdb = protocol_message_2_pars(cdb, cmsg, level + 1); } break; } } + return cdb; } /*-------------------------------------------------------*/ -char *capi_message2str(u8 * msg) + +static _cdebbuf *g_debbuf; +static u_long g_debbuf_lock; +static _cmsg *g_cmsg; + +_cdebbuf *cdebbuf_alloc(void) { + _cdebbuf *cdb; + + if (likely(!test_and_set_bit(1, &g_debbuf_lock))) { + cdb = g_debbuf; + goto init; + } else + cdb = kmalloc(sizeof(_cdebbuf), GFP_ATOMIC); + if (!cdb) + return NULL; + cdb->buf = kmalloc(CDEBUG_SIZE, GFP_ATOMIC); + if (!cdb->buf) { + kfree(cdb); + return NULL; + } + cdb->size = CDEBUG_SIZE; +init: + cdb->buf[0] = 0; + cdb->p = cdb->buf; + cdb->pos = 0; + return cdb; +} - _cmsg cmsg; - p = buf; - p[0] = 0; +void cdebbuf_free(_cdebbuf *cdb) +{ + if (likely(cdb == g_debbuf)) { + test_and_clear_bit(1, &g_debbuf_lock); + return; + } + if (likely(cdb)) + kfree(cdb->buf); + kfree(cdb); +} - cmsg.m = msg; - cmsg.l = 8; - cmsg.p = 0; - byteTRcpy(cmsg.m + 4, &cmsg.Command); - byteTRcpy(cmsg.m + 5, &cmsg.Subcommand); - cmsg.par = cpars[command_2_index(cmsg.Command, cmsg.Subcommand)]; - bufprint("%-26s ID=%03d #0x%04x LEN=%04d\n", - mnames[command_2_index(cmsg.Command, cmsg.Subcommand)], +_cdebbuf *capi_message2str(u8 * msg) +{ + _cdebbuf *cdb; + _cmsg *cmsg; + + cdb = cdebbuf_alloc(); + if (unlikely(!cdb)) + return NULL; + if (likely(cdb == g_debbuf)) + cmsg = g_cmsg; + else + cmsg = kmalloc(sizeof(_cmsg), GFP_ATOMIC); + if (unlikely(!cmsg)) { + cdebbuf_free(cdb); + return NULL; + } + cmsg->m = msg; + cmsg->l = 8; + cmsg->p = 0; + byteTRcpy(cmsg->m + 4, &cmsg->Command); + byteTRcpy(cmsg->m + 5, &cmsg->Subcommand); + cmsg->par = cpars[command_2_index(cmsg->Command, cmsg->Subcommand)]; + + cdb = bufprint(cdb, "%-26s ID=%03d #0x%04x LEN=%04d\n", + mnames[command_2_index(cmsg->Command, cmsg->Subcommand)], ((unsigned short *) msg)[1], ((unsigned short *) msg)[3], ((unsigned short *) msg)[0]); - protocol_message_2_pars(&cmsg, 1); - return buf; + cdb = protocol_message_2_pars(cdb, cmsg, 1); + if (unlikely(cmsg != g_cmsg)) + kfree(cmsg); + return cdb; } -char *capi_cmsg2str(_cmsg * cmsg) +_cdebbuf *capi_cmsg2str(_cmsg * cmsg) { - p = buf; - p[0] = 0; + _cdebbuf *cdb; + + cdb = cdebbuf_alloc(); + if (!cdb) + return NULL; cmsg->l = 8; cmsg->p = 0; - bufprint("%s ID=%03d #0x%04x LEN=%04d\n", + cdb = bufprint(cdb, "%s ID=%03d #0x%04x LEN=%04d\n", mnames[command_2_index(cmsg->Command, cmsg->Subcommand)], ((u16 *) cmsg->m)[1], ((u16 *) cmsg->m)[3], ((u16 *) cmsg->m)[0]); - protocol_message_2_pars(cmsg, 1); - return buf; + cdb = protocol_message_2_pars(cdb, cmsg, 1); + return cdb; } +int __init cdebug_init(void) +{ + g_cmsg= kmalloc(sizeof(_cmsg), GFP_KERNEL); + if (!g_cmsg) + return ENOMEM; + g_debbuf = kmalloc(sizeof(_cdebbuf), GFP_KERNEL); + if (!g_debbuf) { + kfree(g_cmsg); + return ENOMEM; + } + g_debbuf->buf = kmalloc(CDEBUG_GSIZE, GFP_KERNEL); + if (!g_debbuf->buf) { + kfree(g_cmsg); + kfree(g_debbuf); + return ENOMEM;; + } + g_debbuf->size = CDEBUG_GSIZE; + g_debbuf->buf[0] = 0; + g_debbuf->p = g_debbuf->buf; + g_debbuf->pos = 0; + return 0; +} + +void __exit cdebug_exit(void) +{ + if (g_debbuf) + kfree(g_debbuf->buf); + kfree(g_debbuf); + kfree(g_cmsg); +} + +#else /* !CONFIG_CAPI_TRACE */ + +static _cdebbuf g_debbuf = {"CONFIG_CAPI_TRACE not enabled", NULL, 0, 0}; + +_cdebbuf *capi_message2str(u8 * msg) +{ + return &g_debbuf; +} + +_cdebbuf *capi_cmsg2str(_cmsg * cmsg) +{ + return &g_debbuf; +} + +_cdebbuf *cdebbuf_alloc(void) +{ + return &g_debbuf; +} + +void cdebbuf_free(_cdebbuf *cdb) +{ +} + +int __init cdebug_init(void) +{ + return 0; +} + +void __exit cdebug_exit(void) +{ +} + +#endif + +EXPORT_SYMBOL(cdebbuf_alloc); +EXPORT_SYMBOL(cdebbuf_free); EXPORT_SYMBOL(capi_cmsg2message); EXPORT_SYMBOL(capi_message2cmsg); EXPORT_SYMBOL(capi_cmsg_header); diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 783a2552631..3ed34f7a1c4 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -276,10 +276,17 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s int showctl = 0; u8 cmd, subcmd; unsigned long flags; + _cdebbuf *cdb; if (card->cardstate != CARD_RUNNING) { - printk(KERN_INFO "kcapi: controller %d not active, got: %s", - card->cnr, capi_message2str(skb->data)); + cdb = capi_message2str(skb->data); + if (cdb) { + printk(KERN_INFO "kcapi: controller [%03d] not active, got: %s", + card->cnr, cdb->buf); + cdebbuf_free(cdb); + } else + printk(KERN_INFO "kcapi: controller [%03d] not active, cannot trace\n", + card->cnr); goto error; } @@ -295,15 +302,21 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s showctl |= (card->traceflag & 1); if (showctl & 2) { if (showctl & 1) { - printk(KERN_DEBUG "kcapi: got [0x%lx] id#%d %s len=%u\n", - (unsigned long) card->cnr, - CAPIMSG_APPID(skb->data), + printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u\n", + card->cnr, CAPIMSG_APPID(skb->data), capi_cmd2str(cmd, subcmd), CAPIMSG_LEN(skb->data)); } else { - printk(KERN_DEBUG "kcapi: got [0x%lx] %s\n", - (unsigned long) card->cnr, - capi_message2str(skb->data)); + cdb = capi_message2str(skb->data); + if (cdb) { + printk(KERN_DEBUG "kcapi: got [%03d] %s\n", + card->cnr, cdb->buf); + cdebbuf_free(cdb); + } else + printk(KERN_DEBUG "kcapi: got [%03d] id#%d %s len=%u, cannot trace\n", + card->cnr, CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd), + CAPIMSG_LEN(skb->data)); } } @@ -312,8 +325,15 @@ void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *s ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data)); if ((!ap) || (ap->release_in_progress)) { read_unlock_irqrestore(&application_lock, flags); - printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n", - CAPIMSG_APPID(skb->data), capi_message2str(skb->data)); + cdb = capi_message2str(skb->data); + if (cdb) { + printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s)\n", + CAPIMSG_APPID(skb->data), cdb->buf); + cdebbuf_free(cdb); + } else + printk(KERN_ERR "kcapi: handle_message: applid %d state released (%s) cannot trace\n", + CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd)); goto error; } skb_queue_tail(&ap->recv_queue, skb); @@ -332,7 +352,7 @@ void capi_ctr_ready(struct capi_ctr * card) { card->cardstate = CARD_RUNNING; - printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n", + printk(KERN_NOTICE "kcapi: card [%03d] \"%s\" ready.\n", card->cnr, card->name); notify_push(KCI_CONTRUP, card->cnr, 0, 0); @@ -364,7 +384,7 @@ void capi_ctr_reseted(struct capi_ctr * card) capi_ctr_put(card); } - printk(KERN_NOTICE "kcapi: card %d down.\n", card->cnr); + printk(KERN_NOTICE "kcapi: card [%03d] down.\n", card->cnr); notify_push(KCI_CONTRDOWN, card->cnr, 0, 0); } @@ -374,7 +394,7 @@ EXPORT_SYMBOL(capi_ctr_reseted); void capi_ctr_suspend_output(struct capi_ctr *card) { if (!card->blocked) { - printk(KERN_DEBUG "kcapi: card %d suspend\n", card->cnr); + printk(KERN_DEBUG "kcapi: card [%03d] suspend\n", card->cnr); card->blocked = 1; } } @@ -384,7 +404,7 @@ EXPORT_SYMBOL(capi_ctr_suspend_output); void capi_ctr_resume_output(struct capi_ctr *card) { if (card->blocked) { - printk(KERN_DEBUG "kcapi: card %d resume\n", card->cnr); + printk(KERN_DEBUG "kcapi: card [%03d] resume\n", card->cnr); card->blocked = 0; } } @@ -432,7 +452,7 @@ attach_capi_ctr(struct capi_ctr *card) } ncards++; - printk(KERN_NOTICE "kcapi: Controller %d: %s attached\n", + printk(KERN_NOTICE "kcapi: Controller [%03d]: %s attached\n", card->cnr, card->name); return 0; } @@ -451,7 +471,7 @@ int detach_capi_ctr(struct capi_ctr *card) card->procent = NULL; } capi_cards[card->cnr - 1] = NULL; - printk(KERN_NOTICE "kcapi: Controller %d: %s unregistered\n", + printk(KERN_NOTICE "kcapi: Controller [%03d]: %s unregistered\n", card->cnr, card->name); return 0; @@ -623,17 +643,25 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb) showctl |= (card->traceflag & 1); if (showctl & 2) { if (showctl & 1) { - printk(KERN_DEBUG "kcapi: put [%#x] id#%d %s len=%u\n", + printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u\n", CAPIMSG_CONTROLLER(skb->data), CAPIMSG_APPID(skb->data), capi_cmd2str(cmd, subcmd), CAPIMSG_LEN(skb->data)); } else { - printk(KERN_DEBUG "kcapi: put [%#x] %s\n", - CAPIMSG_CONTROLLER(skb->data), - capi_message2str(skb->data)); + _cdebbuf *cdb = capi_message2str(skb->data); + if (cdb) { + printk(KERN_DEBUG "kcapi: put [%03d] %s\n", + CAPIMSG_CONTROLLER(skb->data), + cdb->buf); + cdebbuf_free(cdb); + } else + printk(KERN_DEBUG "kcapi: put [%03d] id#%d %s len=%u cannot trace\n", + CAPIMSG_CONTROLLER(skb->data), + CAPIMSG_APPID(skb->data), + capi_cmd2str(cmd, subcmd), + CAPIMSG_LEN(skb->data)); } - } return card->send_message(card, skb); } @@ -894,7 +922,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data) return -ESRCH; card->traceflag = fdef.flag; - printk(KERN_INFO "kcapi: contr %d set trace=%d\n", + printk(KERN_INFO "kcapi: contr [%03d] set trace=%d\n", card->cnr, card->traceflag); return 0; } @@ -967,7 +995,11 @@ static int __init kcapi_init(void) { char *p; char rev[32]; + int ret; + ret = cdebug_init(); + if (ret) + return ret; kcapi_proc_init(); if ((p = strchr(revision, ':')) != 0 && p[1]) { @@ -988,6 +1020,7 @@ static void __exit kcapi_exit(void) /* make sure all notifiers are finished */ flush_scheduled_work(); + cdebug_exit(); } module_init(kcapi_init); diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile index 5158be0b7ab..e9d3189f56b 100644 --- a/drivers/isdn/gigaset/Makefile +++ b/drivers/isdn/gigaset/Makefile @@ -1,8 +1,9 @@ gigaset-y := common.o interface.o proc.o ev-layer.o i4l.o asyncdata.o usb_gigaset-y := usb-gigaset.o -bas_gigaset-y := bas-gigaset.o isocdata.o ser_gigaset-y := ser-gigaset.o +bas_gigaset-y := bas-gigaset.o isocdata.o -obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o gigaset.o -obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o gigaset.o -obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o gigaset.o +obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset.o +obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o +obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o +obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index f2f108fcec4..00a3be5b862 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -13,11 +13,6 @@ * ===================================================================== */ -/* not set by Kbuild when building both ser_gigaset and usb_gigaset */ -#ifndef KBUILD_MODNAME -#define KBUILD_MODNAME "asy_gigaset" -#endif - #include "gigaset.h" #include <linux/crc-ccitt.h> #include <linux/bitrev.h> diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h index 04574a9d443..0d122bf889d 100644 --- a/drivers/kvm/kvm.h +++ b/drivers/kvm/kvm.h @@ -14,6 +14,7 @@ #include "vmx.h" #include <linux/kvm.h> +#include <linux/kvm_para.h> #define CR0_PE_MASK (1ULL << 0) #define CR0_TS_MASK (1ULL << 3) @@ -237,6 +238,9 @@ struct kvm_vcpu { unsigned long cr0; unsigned long cr2; unsigned long cr3; + gpa_t para_state_gpa; + struct page *para_state_page; + gpa_t hypercall_gpa; unsigned long cr4; unsigned long cr8; u64 pdptrs[4]; /* pae */ @@ -305,6 +309,7 @@ struct kvm { int busy; unsigned long rmap_overflow; struct list_head vm_list; + struct file *filp; }; struct kvm_stat { @@ -339,7 +344,7 @@ struct kvm_arch_ops { int (*vcpu_create)(struct kvm_vcpu *vcpu); void (*vcpu_free)(struct kvm_vcpu *vcpu); - struct kvm_vcpu *(*vcpu_load)(struct kvm_vcpu *vcpu); + void (*vcpu_load)(struct kvm_vcpu *vcpu); void (*vcpu_put)(struct kvm_vcpu *vcpu); void (*vcpu_decache)(struct kvm_vcpu *vcpu); @@ -382,6 +387,8 @@ struct kvm_arch_ops { int (*run)(struct kvm_vcpu *vcpu, struct kvm_run *run); int (*vcpu_setup)(struct kvm_vcpu *vcpu); void (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); + void (*patch_hypercall)(struct kvm_vcpu *vcpu, + unsigned char *hypercall_addr); }; extern struct kvm_stat kvm_stat; @@ -476,6 +483,8 @@ void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes); int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva); void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu); +int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run); + static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code) { @@ -523,7 +532,7 @@ static inline struct kvm_mmu_page *page_header(hpa_t shadow_page) { struct page *page = pfn_to_page(shadow_page >> PAGE_SHIFT); - return (struct kvm_mmu_page *)page->private; + return (struct kvm_mmu_page *)page_private(page); } static inline u16 read_fs(void) diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index af866147ff2..a163bca3897 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -20,6 +20,7 @@ #include <linux/kvm.h> #include <linux/module.h> #include <linux/errno.h> +#include <linux/magic.h> #include <asm/processor.h> #include <linux/percpu.h> #include <linux/gfp.h> @@ -36,6 +37,9 @@ #include <asm/desc.h> #include <linux/sysdev.h> #include <linux/cpu.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/mount.h> #include "x86_emulate.h" #include "segment_descriptor.h" @@ -72,6 +76,8 @@ static struct kvm_stats_debugfs_item { static struct dentry *debugfs_dir; +struct vfsmount *kvmfs_mnt; + #define MAX_IO_MSRS 256 #define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL @@ -90,6 +96,58 @@ struct segment_descriptor_64 { #endif +static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl, + unsigned long arg); + +static struct inode *kvmfs_inode(struct file_operations *fops) +{ + int error = -ENOMEM; + struct inode *inode = new_inode(kvmfs_mnt->mnt_sb); + + if (!inode) + goto eexit_1; + + inode->i_fop = fops; + + /* + * Mark the inode dirty from the very beginning, + * that way it will never be moved to the dirty + * list because mark_inode_dirty() will think + * that it already _is_ on the dirty list. + */ + inode->i_state = I_DIRTY; + inode->i_mode = S_IRUSR | S_IWUSR; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + return inode; + +eexit_1: + return ERR_PTR(error); +} + +static struct file *kvmfs_file(struct inode *inode, void *private_data) +{ + struct file *file = get_empty_filp(); + + if (!file) + return ERR_PTR(-ENFILE); + + file->f_path.mnt = mntget(kvmfs_mnt); + file->f_path.dentry = d_alloc_anon(inode); + if (!file->f_path.dentry) + return ERR_PTR(-ENOMEM); + file->f_mapping = inode->i_mapping; + + file->f_pos = 0; + file->f_flags = O_RDWR; + file->f_op = inode->i_fop; + file->f_mode = FMODE_READ | FMODE_WRITE; + file->f_version = 0; + file->private_data = private_data; + return file; +} + unsigned long segment_base(u16 selector) { struct descriptor_table gdt; @@ -126,10 +184,8 @@ static inline int valid_vcpu(int n) return likely(n >= 0 && n < KVM_MAX_VCPUS); } -int kvm_read_guest(struct kvm_vcpu *vcpu, - gva_t addr, - unsigned long size, - void *dest) +int kvm_read_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size, + void *dest) { unsigned char *host_buf = dest; unsigned long req_size = size; @@ -161,10 +217,8 @@ int kvm_read_guest(struct kvm_vcpu *vcpu, } EXPORT_SYMBOL_GPL(kvm_read_guest); -int kvm_write_guest(struct kvm_vcpu *vcpu, - gva_t addr, - unsigned long size, - void *data) +int kvm_write_guest(struct kvm_vcpu *vcpu, gva_t addr, unsigned long size, + void *data) { unsigned char *host_buf = data; unsigned long req_size = size; @@ -174,12 +228,15 @@ int kvm_write_guest(struct kvm_vcpu *vcpu, unsigned now; unsigned offset; hva_t guest_buf; + gfn_t gfn; paddr = gva_to_hpa(vcpu, addr); if (is_error_hpa(paddr)) break; + gfn = vcpu->mmu.gva_to_gpa(vcpu, addr) >> PAGE_SHIFT; + mark_page_dirty(vcpu->kvm, gfn); guest_buf = (hva_t)kmap_atomic( pfn_to_page(paddr >> PAGE_SHIFT), KM_USER0); offset = addr & ~PAGE_MASK; @@ -195,24 +252,30 @@ int kvm_write_guest(struct kvm_vcpu *vcpu, } EXPORT_SYMBOL_GPL(kvm_write_guest); -static int vcpu_slot(struct kvm_vcpu *vcpu) +/* + * Switches to specified vcpu, until a matching vcpu_put() + */ +static void vcpu_load(struct kvm_vcpu *vcpu) { - return vcpu - vcpu->kvm->vcpus; + mutex_lock(&vcpu->mutex); + kvm_arch_ops->vcpu_load(vcpu); } /* - * Switches to specified vcpu, until a matching vcpu_put() + * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL + * if the slot is not populated. */ -static struct kvm_vcpu *vcpu_load(struct kvm *kvm, int vcpu_slot) +static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot) { - struct kvm_vcpu *vcpu = &kvm->vcpus[vcpu_slot]; + struct kvm_vcpu *vcpu = &kvm->vcpus[slot]; mutex_lock(&vcpu->mutex); - if (unlikely(!vcpu->vmcs)) { + if (!vcpu->vmcs) { mutex_unlock(&vcpu->mutex); return NULL; } - return kvm_arch_ops->vcpu_load(vcpu); + kvm_arch_ops->vcpu_load(vcpu); + return vcpu; } static void vcpu_put(struct kvm_vcpu *vcpu) @@ -221,13 +284,13 @@ static void vcpu_put(struct kvm_vcpu *vcpu) mutex_unlock(&vcpu->mutex); } -static int kvm_dev_open(struct inode *inode, struct file *filp) +static struct kvm *kvm_create_vm(void) { struct kvm *kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL); int i; if (!kvm) - return -ENOMEM; + return ERR_PTR(-ENOMEM); spin_lock_init(&kvm->lock); INIT_LIST_HEAD(&kvm->active_mmu_pages); @@ -243,7 +306,11 @@ static int kvm_dev_open(struct inode *inode, struct file *filp) list_add(&kvm->vm_list, &vm_list); spin_unlock(&kvm_lock); } - filp->private_data = kvm; + return kvm; +} + +static int kvm_dev_open(struct inode *inode, struct file *filp) +{ return 0; } @@ -281,9 +348,10 @@ static void kvm_free_physmem(struct kvm *kvm) static void kvm_free_vcpu(struct kvm_vcpu *vcpu) { - if (!vcpu_load(vcpu->kvm, vcpu_slot(vcpu))) + if (!vcpu->vmcs) return; + vcpu_load(vcpu); kvm_mmu_destroy(vcpu); vcpu_put(vcpu); kvm_arch_ops->vcpu_free(vcpu); @@ -299,14 +367,24 @@ static void kvm_free_vcpus(struct kvm *kvm) static int kvm_dev_release(struct inode *inode, struct file *filp) { - struct kvm *kvm = filp->private_data; + return 0; +} +static void kvm_destroy_vm(struct kvm *kvm) +{ spin_lock(&kvm_lock); list_del(&kvm->vm_list); spin_unlock(&kvm_lock); kvm_free_vcpus(kvm); kvm_free_physmem(kvm); kfree(kvm); +} + +static int kvm_vm_release(struct inode *inode, struct file *filp) +{ + struct kvm *kvm = filp->private_data; + + kvm_destroy_vm(kvm); return 0; } @@ -457,7 +535,7 @@ EXPORT_SYMBOL_GPL(set_cr4); void set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) { if (is_long_mode(vcpu)) { - if ( cr3 & CR3_L_MODE_RESEVED_BITS) { + if (cr3 & CR3_L_MODE_RESEVED_BITS) { printk(KERN_DEBUG "set_cr3: #GP, reserved bits\n"); inject_gp(vcpu); return; @@ -533,55 +611,11 @@ void fx_init(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(fx_init); -/* - * Creates some virtual cpus. Good luck creating more than one. - */ -static int kvm_dev_ioctl_create_vcpu(struct kvm *kvm, int n) +static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot) { - int r; - struct kvm_vcpu *vcpu; - - r = -EINVAL; - if (!valid_vcpu(n)) - goto out; - - vcpu = &kvm->vcpus[n]; - - mutex_lock(&vcpu->mutex); - - if (vcpu->vmcs) { - mutex_unlock(&vcpu->mutex); - return -EEXIST; - } - - vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf, - FX_IMAGE_ALIGN); - vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; - - r = kvm_arch_ops->vcpu_create(vcpu); - if (r < 0) - goto out_free_vcpus; - - r = kvm_mmu_create(vcpu); - if (r < 0) - goto out_free_vcpus; - - kvm_arch_ops->vcpu_load(vcpu); - r = kvm_mmu_setup(vcpu); - if (r >= 0) - r = kvm_arch_ops->vcpu_setup(vcpu); - vcpu_put(vcpu); - - if (r < 0) - goto out_free_vcpus; - - return 0; - -out_free_vcpus: - kvm_free_vcpu(vcpu); - mutex_unlock(&vcpu->mutex); -out: - return r; + spin_lock(&vcpu->kvm->lock); + kvm_mmu_slot_remove_write_access(vcpu, slot); + spin_unlock(&vcpu->kvm->lock); } /* @@ -590,8 +624,8 @@ out: * * Discontiguous memory is allowed, mostly for framebuffers. */ -static int kvm_dev_ioctl_set_memory_region(struct kvm *kvm, - struct kvm_memory_region *mem) +static int kvm_vm_ioctl_set_memory_region(struct kvm *kvm, + struct kvm_memory_region *mem) { int r; gfn_t base_gfn; @@ -674,7 +708,7 @@ raced: | __GFP_ZERO); if (!new.phys_mem[i]) goto out_free; - new.phys_mem[i]->private = 0; + set_page_private(new.phys_mem[i],0); } } @@ -711,9 +745,11 @@ raced: for (i = 0; i < KVM_MAX_VCPUS; ++i) { struct kvm_vcpu *vcpu; - vcpu = vcpu_load(kvm, i); + vcpu = vcpu_load_slot(kvm, i); if (!vcpu) continue; + if (new.flags & KVM_MEM_LOG_DIRTY_PAGES) + do_remove_write_access(vcpu, mem->slot); kvm_mmu_reset_context(vcpu); vcpu_put(vcpu); } @@ -729,18 +765,11 @@ out: return r; } -static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot) -{ - spin_lock(&vcpu->kvm->lock); - kvm_mmu_slot_remove_write_access(vcpu, slot); - spin_unlock(&vcpu->kvm->lock); -} - /* * Get (and clear) the dirty memory log for a memory slot. */ -static int kvm_dev_ioctl_get_dirty_log(struct kvm *kvm, - struct kvm_dirty_log *log) +static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, + struct kvm_dirty_log *log) { struct kvm_memory_slot *memslot; int r, i; @@ -765,21 +794,21 @@ static int kvm_dev_ioctl_get_dirty_log(struct kvm *kvm, if (!memslot->dirty_bitmap) goto out; - n = ALIGN(memslot->npages, 8) / 8; + n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; - for (i = 0; !any && i < n; ++i) + for (i = 0; !any && i < n/sizeof(long); ++i) any = memslot->dirty_bitmap[i]; r = -EFAULT; if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n)) goto out; - if (any) { cleared = 0; for (i = 0; i < KVM_MAX_VCPUS; ++i) { - struct kvm_vcpu *vcpu = vcpu_load(kvm, i); + struct kvm_vcpu *vcpu; + vcpu = vcpu_load_slot(kvm, i); if (!vcpu) continue; if (!cleared) { @@ -903,8 +932,9 @@ static int emulator_read_emulated(unsigned long addr, return X86EMUL_CONTINUE; else { gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr); + if (gpa == UNMAPPED_GVA) - return vcpu_printf(vcpu, "not present\n"), X86EMUL_PROPAGATE_FAULT; + return X86EMUL_PROPAGATE_FAULT; vcpu->mmio_needed = 1; vcpu->mmio_phys_addr = gpa; vcpu->mmio_size = bytes; @@ -928,6 +958,7 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, return 0; page = gfn_to_page(m, gpa >> PAGE_SHIFT); kvm_mmu_pre_write(vcpu, gpa, bytes); + mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT); virt = kmap_atomic(page, KM_USER0); memcpy(virt + offset_in_page(gpa), &val, bytes); kunmap_atomic(virt, KM_USER0); @@ -1142,6 +1173,42 @@ int emulate_instruction(struct kvm_vcpu *vcpu, } EXPORT_SYMBOL_GPL(emulate_instruction); +int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + unsigned long nr, a0, a1, a2, a3, a4, a5, ret; + + kvm_arch_ops->decache_regs(vcpu); + ret = -KVM_EINVAL; +#ifdef CONFIG_X86_64 + if (is_long_mode(vcpu)) { + nr = vcpu->regs[VCPU_REGS_RAX]; + a0 = vcpu->regs[VCPU_REGS_RDI]; + a1 = vcpu->regs[VCPU_REGS_RSI]; + a2 = vcpu->regs[VCPU_REGS_RDX]; + a3 = vcpu->regs[VCPU_REGS_RCX]; + a4 = vcpu->regs[VCPU_REGS_R8]; + a5 = vcpu->regs[VCPU_REGS_R9]; + } else +#endif + { + nr = vcpu->regs[VCPU_REGS_RBX] & -1u; + a0 = vcpu->regs[VCPU_REGS_RAX] & -1u; + a1 = vcpu->regs[VCPU_REGS_RCX] & -1u; + a2 = vcpu->regs[VCPU_REGS_RDX] & -1u; + a3 = vcpu->regs[VCPU_REGS_RSI] & -1u; + a4 = vcpu->regs[VCPU_REGS_RDI] & -1u; + a5 = vcpu->regs[VCPU_REGS_RBP] & -1u; + } + switch (nr) { + default: + ; + } + vcpu->regs[VCPU_REGS_RAX] = ret; + kvm_arch_ops->cache_regs(vcpu); + return 1; +} +EXPORT_SYMBOL_GPL(kvm_hypercall); + static u64 mk_cr_64(u64 curr_cr, u32 new_val) { return (curr_cr & ~((1ULL << 32) - 1)) | new_val; @@ -1208,6 +1275,75 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long val, } } +/* + * Register the para guest with the host: + */ +static int vcpu_register_para(struct kvm_vcpu *vcpu, gpa_t para_state_gpa) +{ + struct kvm_vcpu_para_state *para_state; + hpa_t para_state_hpa, hypercall_hpa; + struct page *para_state_page; + unsigned char *hypercall; + gpa_t hypercall_gpa; + + printk(KERN_DEBUG "kvm: guest trying to enter paravirtual mode\n"); + printk(KERN_DEBUG ".... para_state_gpa: %08Lx\n", para_state_gpa); + + /* + * Needs to be page aligned: + */ + if (para_state_gpa != PAGE_ALIGN(para_state_gpa)) + goto err_gp; + + para_state_hpa = gpa_to_hpa(vcpu, para_state_gpa); + printk(KERN_DEBUG ".... para_state_hpa: %08Lx\n", para_state_hpa); + if (is_error_hpa(para_state_hpa)) + goto err_gp; + + mark_page_dirty(vcpu->kvm, para_state_gpa >> PAGE_SHIFT); + para_state_page = pfn_to_page(para_state_hpa >> PAGE_SHIFT); + para_state = kmap_atomic(para_state_page, KM_USER0); + + printk(KERN_DEBUG ".... guest version: %d\n", para_state->guest_version); + printk(KERN_DEBUG ".... size: %d\n", para_state->size); + + para_state->host_version = KVM_PARA_API_VERSION; + /* + * We cannot support guests that try to register themselves + * with a newer API version than the host supports: + */ + if (para_state->guest_version > KVM_PARA_API_VERSION) { + para_state->ret = -KVM_EINVAL; + goto err_kunmap_skip; + } + + hypercall_gpa = para_state->hypercall_gpa; + hypercall_hpa = gpa_to_hpa(vcpu, hypercall_gpa); + printk(KERN_DEBUG ".... hypercall_hpa: %08Lx\n", hypercall_hpa); + if (is_error_hpa(hypercall_hpa)) { + para_state->ret = -KVM_EINVAL; + goto err_kunmap_skip; + } + + printk(KERN_DEBUG "kvm: para guest successfully registered.\n"); + vcpu->para_state_page = para_state_page; + vcpu->para_state_gpa = para_state_gpa; + vcpu->hypercall_gpa = hypercall_gpa; + + mark_page_dirty(vcpu->kvm, hypercall_gpa >> PAGE_SHIFT); + hypercall = kmap_atomic(pfn_to_page(hypercall_hpa >> PAGE_SHIFT), + KM_USER1) + (hypercall_hpa & ~PAGE_MASK); + kvm_arch_ops->patch_hypercall(vcpu, hypercall); + kunmap_atomic(hypercall, KM_USER1); + + para_state->ret = 0; +err_kunmap_skip: + kunmap_atomic(para_state, KM_USER0); + return 0; +err_gp: + return 1; +} + int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) { u64 data; @@ -1316,6 +1452,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data) case MSR_IA32_MISC_ENABLE: vcpu->ia32_misc_enable_msr = data; break; + /* + * This is the 'probe whether the host is KVM' logic: + */ + case MSR_KVM_API_MAGIC: + return vcpu_register_para(vcpu, data); + default: printk(KERN_ERR "kvm: unhandled wrmsr: 0x%x\n", msr); return 1; @@ -1338,8 +1480,7 @@ void kvm_resched(struct kvm_vcpu *vcpu) { vcpu_put(vcpu); cond_resched(); - /* Cannot fail - no vcpu unplug yet. */ - vcpu_load(vcpu->kvm, vcpu_slot(vcpu)); + vcpu_load(vcpu); } EXPORT_SYMBOL_GPL(kvm_resched); @@ -1361,17 +1502,11 @@ void save_msrs(struct vmx_msr_entry *e, int n) } EXPORT_SYMBOL_GPL(save_msrs); -static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run) +static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { - struct kvm_vcpu *vcpu; int r; - if (!valid_vcpu(kvm_run->vcpu)) - return -EINVAL; - - vcpu = vcpu_load(kvm, kvm_run->vcpu); - if (!vcpu) - return -ENOENT; + vcpu_load(vcpu); /* re-sync apic's tpr */ vcpu->cr8 = kvm_run->cr8; @@ -1394,16 +1529,10 @@ static int kvm_dev_ioctl_run(struct kvm *kvm, struct kvm_run *kvm_run) return r; } -static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs) +static int kvm_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, + struct kvm_regs *regs) { - struct kvm_vcpu *vcpu; - - if (!valid_vcpu(regs->vcpu)) - return -EINVAL; - - vcpu = vcpu_load(kvm, regs->vcpu); - if (!vcpu) - return -ENOENT; + vcpu_load(vcpu); kvm_arch_ops->cache_regs(vcpu); @@ -1440,16 +1569,10 @@ static int kvm_dev_ioctl_get_regs(struct kvm *kvm, struct kvm_regs *regs) return 0; } -static int kvm_dev_ioctl_set_regs(struct kvm *kvm, struct kvm_regs *regs) +static int kvm_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, + struct kvm_regs *regs) { - struct kvm_vcpu *vcpu; - - if (!valid_vcpu(regs->vcpu)) - return -EINVAL; - - vcpu = vcpu_load(kvm, regs->vcpu); - if (!vcpu) - return -ENOENT; + vcpu_load(vcpu); vcpu->regs[VCPU_REGS_RAX] = regs->rax; vcpu->regs[VCPU_REGS_RBX] = regs->rbx; @@ -1486,16 +1609,12 @@ static void get_segment(struct kvm_vcpu *vcpu, return kvm_arch_ops->get_segment(vcpu, var, seg); } -static int kvm_dev_ioctl_get_sregs(struct kvm *kvm, struct kvm_sregs *sregs) +static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs) { - struct kvm_vcpu *vcpu; struct descriptor_table dt; - if (!valid_vcpu(sregs->vcpu)) - return -EINVAL; - vcpu = vcpu_load(kvm, sregs->vcpu); - if (!vcpu) - return -ENOENT; + vcpu_load(vcpu); get_segment(vcpu, &sregs->cs, VCPU_SREG_CS); get_segment(vcpu, &sregs->ds, VCPU_SREG_DS); @@ -1537,18 +1656,14 @@ static void set_segment(struct kvm_vcpu *vcpu, return kvm_arch_ops->set_segment(vcpu, var, seg); } -static int kvm_dev_ioctl_set_sregs(struct kvm *kvm, struct kvm_sregs *sregs) +static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, + struct kvm_sregs *sregs) { - struct kvm_vcpu *vcpu; int mmu_reset_needed = 0; int i; struct descriptor_table dt; - if (!valid_vcpu(sregs->vcpu)) - return -EINVAL; - vcpu = vcpu_load(kvm, sregs->vcpu); - if (!vcpu) - return -ENOENT; + vcpu_load(vcpu); set_segment(vcpu, &sregs->cs, VCPU_SREG_CS); set_segment(vcpu, &sregs->ds, VCPU_SREG_DS); @@ -1654,20 +1769,14 @@ static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) * * @return number of msrs set successfully. */ -static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs, +static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, struct kvm_msr_entry *entries, int (*do_msr)(struct kvm_vcpu *vcpu, unsigned index, u64 *data)) { - struct kvm_vcpu *vcpu; int i; - if (!valid_vcpu(msrs->vcpu)) - return -EINVAL; - - vcpu = vcpu_load(kvm, msrs->vcpu); - if (!vcpu) - return -ENOENT; + vcpu_load(vcpu); for (i = 0; i < msrs->nmsrs; ++i) if (do_msr(vcpu, entries[i].index, &entries[i].data)) @@ -1683,7 +1792,7 @@ static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs, * * @return number of msrs set successfully. */ -static int msr_io(struct kvm *kvm, struct kvm_msrs __user *user_msrs, +static int msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs, int (*do_msr)(struct kvm_vcpu *vcpu, unsigned index, u64 *data), int writeback) @@ -1711,7 +1820,7 @@ static int msr_io(struct kvm *kvm, struct kvm_msrs __user *user_msrs, if (copy_from_user(entries, user_msrs->entries, size)) goto out_free; - r = n = __msr_io(kvm, &msrs, entries, do_msr); + r = n = __msr_io(vcpu, &msrs, entries, do_msr); if (r < 0) goto out_free; @@ -1730,38 +1839,31 @@ out: /* * Translate a guest virtual address to a guest physical address. */ -static int kvm_dev_ioctl_translate(struct kvm *kvm, struct kvm_translation *tr) +static int kvm_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, + struct kvm_translation *tr) { unsigned long vaddr = tr->linear_address; - struct kvm_vcpu *vcpu; gpa_t gpa; - vcpu = vcpu_load(kvm, tr->vcpu); - if (!vcpu) - return -ENOENT; - spin_lock(&kvm->lock); + vcpu_load(vcpu); + spin_lock(&vcpu->kvm->lock); gpa = vcpu->mmu.gva_to_gpa(vcpu, vaddr); tr->physical_address = gpa; tr->valid = gpa != UNMAPPED_GVA; tr->writeable = 1; tr->usermode = 0; - spin_unlock(&kvm->lock); + spin_unlock(&vcpu->kvm->lock); vcpu_put(vcpu); return 0; } -static int kvm_dev_ioctl_interrupt(struct kvm *kvm, struct kvm_interrupt *irq) +static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, + struct kvm_interrupt *irq) { - struct kvm_vcpu *vcpu; - - if (!valid_vcpu(irq->vcpu)) - return -EINVAL; if (irq->irq < 0 || irq->irq >= 256) return -EINVAL; - vcpu = vcpu_load(kvm, irq->vcpu); - if (!vcpu) - return -ENOENT; + vcpu_load(vcpu); set_bit(irq->irq, vcpu->irq_pending); set_bit(irq->irq / BITS_PER_LONG, &vcpu->irq_summary); @@ -1771,17 +1873,12 @@ static int kvm_dev_ioctl_interrupt(struct kvm *kvm, struct kvm_interrupt *irq) return 0; } -static int kvm_dev_ioctl_debug_guest(struct kvm *kvm, - struct kvm_debug_guest *dbg) +static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu, + struct kvm_debug_guest *dbg) { - struct kvm_vcpu *vcpu; int r; - if (!valid_vcpu(dbg->vcpu)) - return -EINVAL; - vcpu = vcpu_load(kvm, dbg->vcpu); - if (!vcpu) - return -ENOENT; + vcpu_load(vcpu); r = kvm_arch_ops->set_guest_debug(vcpu, dbg); @@ -1790,30 +1887,129 @@ static int kvm_dev_ioctl_debug_guest(struct kvm *kvm, return r; } -static long kvm_dev_ioctl(struct file *filp, - unsigned int ioctl, unsigned long arg) +static int kvm_vcpu_release(struct inode *inode, struct file *filp) { - struct kvm *kvm = filp->private_data; + struct kvm_vcpu *vcpu = filp->private_data; + + fput(vcpu->kvm->filp); + return 0; +} + +static struct file_operations kvm_vcpu_fops = { + .release = kvm_vcpu_release, + .unlocked_ioctl = kvm_vcpu_ioctl, + .compat_ioctl = kvm_vcpu_ioctl, +}; + +/* + * Allocates an inode for the vcpu. + */ +static int create_vcpu_fd(struct kvm_vcpu *vcpu) +{ + int fd, r; + struct inode *inode; + struct file *file; + + atomic_inc(&vcpu->kvm->filp->f_count); + inode = kvmfs_inode(&kvm_vcpu_fops); + if (IS_ERR(inode)) { + r = PTR_ERR(inode); + goto out1; + } + + file = kvmfs_file(inode, vcpu); + if (IS_ERR(file)) { + r = PTR_ERR(file); + goto out2; + } + + r = get_unused_fd(); + if (r < 0) + goto out3; + fd = r; + fd_install(fd, file); + + return fd; + +out3: + fput(file); +out2: + iput(inode); +out1: + fput(vcpu->kvm->filp); + return r; +} + +/* + * Creates some virtual cpus. Good luck creating more than one. + */ +static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n) +{ + int r; + struct kvm_vcpu *vcpu; + + r = -EINVAL; + if (!valid_vcpu(n)) + goto out; + + vcpu = &kvm->vcpus[n]; + + mutex_lock(&vcpu->mutex); + + if (vcpu->vmcs) { + mutex_unlock(&vcpu->mutex); + return -EEXIST; + } + + vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf, + FX_IMAGE_ALIGN); + vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE; + + r = kvm_arch_ops->vcpu_create(vcpu); + if (r < 0) + goto out_free_vcpus; + + r = kvm_mmu_create(vcpu); + if (r < 0) + goto out_free_vcpus; + + kvm_arch_ops->vcpu_load(vcpu); + r = kvm_mmu_setup(vcpu); + if (r >= 0) + r = kvm_arch_ops->vcpu_setup(vcpu); + vcpu_put(vcpu); + + if (r < 0) + goto out_free_vcpus; + + r = create_vcpu_fd(vcpu); + if (r < 0) + goto out_free_vcpus; + + return r; + +out_free_vcpus: + kvm_free_vcpu(vcpu); + mutex_unlock(&vcpu->mutex); +out: + return r; +} + +static long kvm_vcpu_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + struct kvm_vcpu *vcpu = filp->private_data; void __user *argp = (void __user *)arg; int r = -EINVAL; switch (ioctl) { - case KVM_GET_API_VERSION: - r = KVM_API_VERSION; - break; - case KVM_CREATE_VCPU: { - r = kvm_dev_ioctl_create_vcpu(kvm, arg); - if (r) - goto out; - break; - } case KVM_RUN: { struct kvm_run kvm_run; r = -EFAULT; if (copy_from_user(&kvm_run, argp, sizeof kvm_run)) goto out; - r = kvm_dev_ioctl_run(kvm, &kvm_run); + r = kvm_vcpu_ioctl_run(vcpu, &kvm_run); if (r < 0 && r != -EINTR) goto out; if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) { @@ -1825,10 +2021,8 @@ static long kvm_dev_ioctl(struct file *filp, case KVM_GET_REGS: { struct kvm_regs kvm_regs; - r = -EFAULT; - if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) - goto out; - r = kvm_dev_ioctl_get_regs(kvm, &kvm_regs); + memset(&kvm_regs, 0, sizeof kvm_regs); + r = kvm_vcpu_ioctl_get_regs(vcpu, &kvm_regs); if (r) goto out; r = -EFAULT; @@ -1843,7 +2037,7 @@ static long kvm_dev_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&kvm_regs, argp, sizeof kvm_regs)) goto out; - r = kvm_dev_ioctl_set_regs(kvm, &kvm_regs); + r = kvm_vcpu_ioctl_set_regs(vcpu, &kvm_regs); if (r) goto out; r = 0; @@ -1852,10 +2046,8 @@ static long kvm_dev_ioctl(struct file *filp, case KVM_GET_SREGS: { struct kvm_sregs kvm_sregs; - r = -EFAULT; - if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) - goto out; - r = kvm_dev_ioctl_get_sregs(kvm, &kvm_sregs); + memset(&kvm_sregs, 0, sizeof kvm_sregs); + r = kvm_vcpu_ioctl_get_sregs(vcpu, &kvm_sregs); if (r) goto out; r = -EFAULT; @@ -1870,7 +2062,7 @@ static long kvm_dev_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs)) goto out; - r = kvm_dev_ioctl_set_sregs(kvm, &kvm_sregs); + r = kvm_vcpu_ioctl_set_sregs(vcpu, &kvm_sregs); if (r) goto out; r = 0; @@ -1882,7 +2074,7 @@ static long kvm_dev_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&tr, argp, sizeof tr)) goto out; - r = kvm_dev_ioctl_translate(kvm, &tr); + r = kvm_vcpu_ioctl_translate(vcpu, &tr); if (r) goto out; r = -EFAULT; @@ -1897,7 +2089,7 @@ static long kvm_dev_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&irq, argp, sizeof irq)) goto out; - r = kvm_dev_ioctl_interrupt(kvm, &irq); + r = kvm_vcpu_ioctl_interrupt(vcpu, &irq); if (r) goto out; r = 0; @@ -1909,19 +2101,45 @@ static long kvm_dev_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&dbg, argp, sizeof dbg)) goto out; - r = kvm_dev_ioctl_debug_guest(kvm, &dbg); + r = kvm_vcpu_ioctl_debug_guest(vcpu, &dbg); if (r) goto out; r = 0; break; } + case KVM_GET_MSRS: + r = msr_io(vcpu, argp, get_msr, 1); + break; + case KVM_SET_MSRS: + r = msr_io(vcpu, argp, do_set_msr, 0); + break; + default: + ; + } +out: + return r; +} + +static long kvm_vm_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + struct kvm *kvm = filp->private_data; + void __user *argp = (void __user *)arg; + int r = -EINVAL; + + switch (ioctl) { + case KVM_CREATE_VCPU: + r = kvm_vm_ioctl_create_vcpu(kvm, arg); + if (r < 0) + goto out; + break; case KVM_SET_MEMORY_REGION: { struct kvm_memory_region kvm_mem; r = -EFAULT; if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem)) goto out; - r = kvm_dev_ioctl_set_memory_region(kvm, &kvm_mem); + r = kvm_vm_ioctl_set_memory_region(kvm, &kvm_mem); if (r) goto out; break; @@ -1932,16 +2150,112 @@ static long kvm_dev_ioctl(struct file *filp, r = -EFAULT; if (copy_from_user(&log, argp, sizeof log)) goto out; - r = kvm_dev_ioctl_get_dirty_log(kvm, &log); + r = kvm_vm_ioctl_get_dirty_log(kvm, &log); if (r) goto out; break; } - case KVM_GET_MSRS: - r = msr_io(kvm, argp, get_msr, 1); + default: + ; + } +out: + return r; +} + +static struct page *kvm_vm_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + struct kvm *kvm = vma->vm_file->private_data; + unsigned long pgoff; + struct kvm_memory_slot *slot; + struct page *page; + + *type = VM_FAULT_MINOR; + pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + slot = gfn_to_memslot(kvm, pgoff); + if (!slot) + return NOPAGE_SIGBUS; + page = gfn_to_page(slot, pgoff); + if (!page) + return NOPAGE_SIGBUS; + get_page(page); + return page; +} + +static struct vm_operations_struct kvm_vm_vm_ops = { + .nopage = kvm_vm_nopage, +}; + +static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma) +{ + vma->vm_ops = &kvm_vm_vm_ops; + return 0; +} + +static struct file_operations kvm_vm_fops = { + .release = kvm_vm_release, + .unlocked_ioctl = kvm_vm_ioctl, + .compat_ioctl = kvm_vm_ioctl, + .mmap = kvm_vm_mmap, +}; + +static int kvm_dev_ioctl_create_vm(void) +{ + int fd, r; + struct inode *inode; + struct file *file; + struct kvm *kvm; + + inode = kvmfs_inode(&kvm_vm_fops); + if (IS_ERR(inode)) { + r = PTR_ERR(inode); + goto out1; + } + + kvm = kvm_create_vm(); + if (IS_ERR(kvm)) { + r = PTR_ERR(kvm); + goto out2; + } + + file = kvmfs_file(inode, kvm); + if (IS_ERR(file)) { + r = PTR_ERR(file); + goto out3; + } + kvm->filp = file; + + r = get_unused_fd(); + if (r < 0) + goto out4; + fd = r; + fd_install(fd, file); + + return fd; + +out4: + fput(file); +out3: + kvm_destroy_vm(kvm); +out2: + iput(inode); +out1: + return r; +} + +static long kvm_dev_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int r = -EINVAL; + + switch (ioctl) { + case KVM_GET_API_VERSION: + r = KVM_API_VERSION; break; - case KVM_SET_MSRS: - r = msr_io(kvm, argp, do_set_msr, 0); + case KVM_CREATE_VM: + r = kvm_dev_ioctl_create_vm(); break; case KVM_GET_MSR_INDEX_LIST: { struct kvm_msr_list __user *user_msr_list = argp; @@ -1977,43 +2291,11 @@ out: return r; } -static struct page *kvm_dev_nopage(struct vm_area_struct *vma, - unsigned long address, - int *type) -{ - struct kvm *kvm = vma->vm_file->private_data; - unsigned long pgoff; - struct kvm_memory_slot *slot; - struct page *page; - - *type = VM_FAULT_MINOR; - pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - slot = gfn_to_memslot(kvm, pgoff); - if (!slot) - return NOPAGE_SIGBUS; - page = gfn_to_page(slot, pgoff); - if (!page) - return NOPAGE_SIGBUS; - get_page(page); - return page; -} - -static struct vm_operations_struct kvm_dev_vm_ops = { - .nopage = kvm_dev_nopage, -}; - -static int kvm_dev_mmap(struct file *file, struct vm_area_struct *vma) -{ - vma->vm_ops = &kvm_dev_vm_ops; - return 0; -} - static struct file_operations kvm_chardev_ops = { .open = kvm_dev_open, .release = kvm_dev_release, .unlocked_ioctl = kvm_dev_ioctl, .compat_ioctl = kvm_dev_ioctl, - .mmap = kvm_dev_mmap, }; static struct miscdevice kvm_dev = { @@ -2080,13 +2362,17 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val, int cpu = (long)v; switch (val) { - case CPU_DEAD: + case CPU_DOWN_PREPARE: case CPU_UP_CANCELED: + printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n", + cpu); decache_vcpus_on_cpu(cpu); smp_call_function_single(cpu, kvm_arch_ops->hardware_disable, NULL, 0, 1); break; - case CPU_UP_PREPARE: + case CPU_ONLINE: + printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n", + cpu); smp_call_function_single(cpu, kvm_arch_ops->hardware_enable, NULL, 0, 1); break; @@ -2121,13 +2407,13 @@ static void kvm_exit_debug(void) static int kvm_suspend(struct sys_device *dev, pm_message_t state) { decache_vcpus_on_cpu(raw_smp_processor_id()); - on_each_cpu(kvm_arch_ops->hardware_disable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1); return 0; } static int kvm_resume(struct sys_device *dev) { - on_each_cpu(kvm_arch_ops->hardware_enable, 0, 0, 1); + on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1); return 0; } @@ -2144,6 +2430,18 @@ static struct sys_device kvm_sysdev = { hpa_t bad_page_address; +static int kvmfs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt) +{ + return get_sb_pseudo(fs_type, "kvm:", NULL, KVMFS_SUPER_MAGIC, mnt); +} + +static struct file_system_type kvm_fs_type = { + .name = "kvmfs", + .get_sb = kvmfs_get_sb, + .kill_sb = kill_anon_super, +}; + int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module) { int r; @@ -2220,8 +2518,16 @@ void kvm_exit_arch(void) static __init int kvm_init(void) { static struct page *bad_page; - int r = 0; + int r; + + r = register_filesystem(&kvm_fs_type); + if (r) + goto out3; + kvmfs_mnt = kern_mount(&kvm_fs_type); + r = PTR_ERR(kvmfs_mnt); + if (IS_ERR(kvmfs_mnt)) + goto out2; kvm_init_debug(); kvm_init_msr_list(); @@ -2234,10 +2540,14 @@ static __init int kvm_init(void) bad_page_address = page_to_pfn(bad_page) << PAGE_SHIFT; memset(__va(bad_page_address), 0, PAGE_SIZE); - return r; + return 0; out: kvm_exit_debug(); + mntput(kvmfs_mnt); +out2: + unregister_filesystem(&kvm_fs_type); +out3: return r; } @@ -2245,6 +2555,8 @@ static __exit void kvm_exit(void) { kvm_exit_debug(); __free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT)); + mntput(kvmfs_mnt); + unregister_filesystem(&kvm_fs_type); } module_init(kvm_init) diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h index 74cc862f493..624f1ca4865 100644 --- a/drivers/kvm/kvm_svm.h +++ b/drivers/kvm/kvm_svm.h @@ -1,6 +1,7 @@ #ifndef __KVM_SVM_H #define __KVM_SVM_H +#include <linux/kernel.h> #include <linux/types.h> #include <linux/list.h> #include <asm/msr.h> @@ -18,7 +19,7 @@ static const u32 host_save_msrs[] = { MSR_IA32_LASTBRANCHTOIP, MSR_IA32_LASTINTFROMIP,MSR_IA32_LASTINTTOIP,*/ }; -#define NR_HOST_SAVE_MSRS (sizeof(host_save_msrs) / sizeof(*host_save_msrs)) +#define NR_HOST_SAVE_MSRS ARRAY_SIZE(host_save_msrs) #define NUM_DB_REGS 4 struct vcpu_svm { diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c index be793770f31..a1a93368f31 100644 --- a/drivers/kvm/mmu.c +++ b/drivers/kvm/mmu.c @@ -298,18 +298,18 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte) if (!is_rmap_pte(*spte)) return; page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); - if (!page->private) { + if (!page_private(page)) { rmap_printk("rmap_add: %p %llx 0->1\n", spte, *spte); - page->private = (unsigned long)spte; - } else if (!(page->private & 1)) { + set_page_private(page,(unsigned long)spte); + } else if (!(page_private(page) & 1)) { rmap_printk("rmap_add: %p %llx 1->many\n", spte, *spte); desc = mmu_alloc_rmap_desc(vcpu); - desc->shadow_ptes[0] = (u64 *)page->private; + desc->shadow_ptes[0] = (u64 *)page_private(page); desc->shadow_ptes[1] = spte; - page->private = (unsigned long)desc | 1; + set_page_private(page,(unsigned long)desc | 1); } else { rmap_printk("rmap_add: %p %llx many->many\n", spte, *spte); - desc = (struct kvm_rmap_desc *)(page->private & ~1ul); + desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul); while (desc->shadow_ptes[RMAP_EXT-1] && desc->more) desc = desc->more; if (desc->shadow_ptes[RMAP_EXT-1]) { @@ -337,12 +337,12 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu, if (j != 0) return; if (!prev_desc && !desc->more) - page->private = (unsigned long)desc->shadow_ptes[0]; + set_page_private(page,(unsigned long)desc->shadow_ptes[0]); else if (prev_desc) prev_desc->more = desc->more; else - page->private = (unsigned long)desc->more | 1; + set_page_private(page,(unsigned long)desc->more | 1); mmu_free_rmap_desc(vcpu, desc); } @@ -356,20 +356,20 @@ static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte) if (!is_rmap_pte(*spte)) return; page = pfn_to_page((*spte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT); - if (!page->private) { + if (!page_private(page)) { printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte); BUG(); - } else if (!(page->private & 1)) { + } else if (!(page_private(page) & 1)) { rmap_printk("rmap_remove: %p %llx 1->0\n", spte, *spte); - if ((u64 *)page->private != spte) { + if ((u64 *)page_private(page) != spte) { printk(KERN_ERR "rmap_remove: %p %llx 1->BUG\n", spte, *spte); BUG(); } - page->private = 0; + set_page_private(page,0); } else { rmap_printk("rmap_remove: %p %llx many->many\n", spte, *spte); - desc = (struct kvm_rmap_desc *)(page->private & ~1ul); + desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul); prev_desc = NULL; while (desc) { for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i) @@ -398,11 +398,11 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn) BUG_ON(!slot); page = gfn_to_page(slot, gfn); - while (page->private) { - if (!(page->private & 1)) - spte = (u64 *)page->private; + while (page_private(page)) { + if (!(page_private(page) & 1)) + spte = (u64 *)page_private(page); else { - desc = (struct kvm_rmap_desc *)(page->private & ~1ul); + desc = (struct kvm_rmap_desc *)(page_private(page) & ~1ul); spte = desc->shadow_ptes[0]; } BUG_ON(!spte); @@ -1218,7 +1218,7 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu) INIT_LIST_HEAD(&page_header->link); if ((page = alloc_page(GFP_KERNEL)) == NULL) goto error_1; - page->private = (unsigned long)page_header; + set_page_private(page, (unsigned long)page_header); page_header->page_hpa = (hpa_t)page_to_pfn(page) << PAGE_SHIFT; memset(__va(page_header->page_hpa), 0, PAGE_SIZE); list_add(&page_header->link, &vcpu->free_pages); diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h index b6b90e9e130..f3bcee90465 100644 --- a/drivers/kvm/paging_tmpl.h +++ b/drivers/kvm/paging_tmpl.h @@ -128,8 +128,10 @@ static int FNAME(walk_addr)(struct guest_walker *walker, goto access_error; #endif - if (!(*ptep & PT_ACCESSED_MASK)) - *ptep |= PT_ACCESSED_MASK; /* avoid rmw */ + if (!(*ptep & PT_ACCESSED_MASK)) { + mark_page_dirty(vcpu->kvm, table_gfn); + *ptep |= PT_ACCESSED_MASK; + } if (walker->level == PT_PAGE_TABLE_LEVEL) { walker->gfn = (*ptep & PT_BASE_ADDR_MASK) @@ -185,6 +187,12 @@ static void FNAME(release_walker)(struct guest_walker *walker) kunmap_atomic(walker->table, KM_USER0); } +static void FNAME(mark_pagetable_dirty)(struct kvm *kvm, + struct guest_walker *walker) +{ + mark_page_dirty(kvm, walker->table_gfn[walker->level - 1]); +} + static void FNAME(set_pte)(struct kvm_vcpu *vcpu, u64 guest_pte, u64 *shadow_pte, u64 access_bits, gfn_t gfn) { @@ -348,12 +356,15 @@ static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu, } else if (kvm_mmu_lookup_page(vcpu, gfn)) { pgprintk("%s: found shadow page for %lx, marking ro\n", __FUNCTION__, gfn); + mark_page_dirty(vcpu->kvm, gfn); + FNAME(mark_pagetable_dirty)(vcpu->kvm, walker); *guest_ent |= PT_DIRTY_MASK; *write_pt = 1; return 0; } mark_page_dirty(vcpu->kvm, gfn); *shadow_ent |= PT_WRITABLE_MASK; + FNAME(mark_pagetable_dirty)(vcpu->kvm, walker); *guest_ent |= PT_DIRTY_MASK; rmap_add(vcpu, shadow_ent); @@ -430,9 +441,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, /* * mmio: emulate if accessible, otherwise its a guest fault. */ - if (is_io_pte(*shadow_pte)) { + if (is_io_pte(*shadow_pte)) return 1; - } ++kvm_stat.pf_fixed; kvm_mmu_audit(vcpu, "post page fault (fixed)"); diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 83da4ea150a..3d8ea7ac2ec 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -15,6 +15,7 @@ */ #include <linux/module.h> +#include <linux/kernel.h> #include <linux/vmalloc.h> #include <linux/highmem.h> #include <linux/profile.h> @@ -75,7 +76,7 @@ struct svm_init_data { static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000}; -#define NUM_MSR_MAPS (sizeof(msrpm_ranges) / sizeof(*msrpm_ranges)) +#define NUM_MSR_MAPS ARRAY_SIZE(msrpm_ranges) #define MSRS_RANGE_SIZE 2048 #define MSRS_IN_RANGE (MSRS_RANGE_SIZE * 8 / 2) @@ -485,6 +486,7 @@ static void init_vmcb(struct vmcb *vmcb) control->intercept = (1ULL << INTERCEPT_INTR) | (1ULL << INTERCEPT_NMI) | + (1ULL << INTERCEPT_SMI) | /* * selective cr0 intercept bug? * 0: 0f 22 d8 mov %eax,%cr3 @@ -553,7 +555,7 @@ static void init_vmcb(struct vmcb *vmcb) * cr0 val on cpu init should be 0x60000010, we enable cpu * cache by default. the orderly way is to enable cache in bios. */ - save->cr0 = 0x00000010 | CR0_PG_MASK; + save->cr0 = 0x00000010 | CR0_PG_MASK | CR0_WP_MASK; save->cr4 = CR4_PAE_MASK; /* rdx = ?? */ } @@ -598,10 +600,9 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu) kfree(vcpu->svm); } -static struct kvm_vcpu *svm_vcpu_load(struct kvm_vcpu *vcpu) +static void svm_vcpu_load(struct kvm_vcpu *vcpu) { get_cpu(); - return vcpu; } static void svm_vcpu_put(struct kvm_vcpu *vcpu) @@ -1042,22 +1043,22 @@ static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) addr_mask = io_adress(vcpu, _in, &kvm_run->io.address); if (!addr_mask) { - printk(KERN_DEBUG "%s: get io address failed\n", __FUNCTION__); + printk(KERN_DEBUG "%s: get io address failed\n", + __FUNCTION__); return 1; } if (kvm_run->io.rep) { - kvm_run->io.count = vcpu->regs[VCPU_REGS_RCX] & addr_mask; + kvm_run->io.count + = vcpu->regs[VCPU_REGS_RCX] & addr_mask; kvm_run->io.string_down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0; } - } else { + } else kvm_run->io.value = vcpu->svm->vmcb->save.rax; - } return 0; } - static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { return 1; @@ -1075,6 +1076,12 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } +static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + vcpu->svm->vmcb->save.rip += 3; + return kvm_hypercall(vcpu, kvm_run); +} + static int invalid_op_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { inject_ud(vcpu); @@ -1275,7 +1282,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu, [SVM_EXIT_TASK_SWITCH] = task_switch_interception, [SVM_EXIT_SHUTDOWN] = shutdown_interception, [SVM_EXIT_VMRUN] = invalid_op_interception, - [SVM_EXIT_VMMCALL] = invalid_op_interception, + [SVM_EXIT_VMMCALL] = vmmcall_interception, [SVM_EXIT_VMLOAD] = invalid_op_interception, [SVM_EXIT_VMSAVE] = invalid_op_interception, [SVM_EXIT_STGI] = invalid_op_interception, @@ -1297,7 +1304,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) __FUNCTION__, vcpu->svm->vmcb->control.exit_int_info, exit_code); - if (exit_code >= sizeof(svm_exit_handlers) / sizeof(*svm_exit_handlers) + if (exit_code >= ARRAY_SIZE(svm_exit_handlers) || svm_exit_handlers[exit_code] == 0) { kvm_run->exit_reason = KVM_EXIT_UNKNOWN; printk(KERN_ERR "%s: 0x%x @ 0x%llx cr0 0x%lx rflags 0x%llx\n", @@ -1668,6 +1675,18 @@ static int is_disabled(void) return 0; } +static void +svm_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) +{ + /* + * Patch in the VMMCALL instruction: + */ + hypercall[0] = 0x0f; + hypercall[1] = 0x01; + hypercall[2] = 0xd9; + hypercall[3] = 0xc3; +} + static struct kvm_arch_ops svm_arch_ops = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, @@ -1716,6 +1735,7 @@ static struct kvm_arch_ops svm_arch_ops = { .run = svm_vcpu_run, .skip_emulated_instruction = skip_emulated_instruction, .vcpu_setup = svm_vcpu_setup, + .patch_hypercall = svm_patch_hypercall, }; static int __init svm_init(void) diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index fd4e9173438..c07178e6112 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -19,6 +19,7 @@ #include "vmx.h" #include "kvm_vmx.h" #include <linux/module.h> +#include <linux/kernel.h> #include <linux/mm.h> #include <linux/highmem.h> #include <linux/profile.h> @@ -27,7 +28,6 @@ #include "segment_descriptor.h" - MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); @@ -76,7 +76,7 @@ static const u32 vmx_msr_index[] = { #endif MSR_EFER, MSR_K6_STAR, }; -#define NR_VMX_MSR (sizeof(vmx_msr_index) / sizeof(*vmx_msr_index)) +#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index) static inline int is_page_fault(u32 intr_info) { @@ -204,7 +204,7 @@ static void vmcs_write64(unsigned long field, u64 value) * Switches to specified vcpu, until a matching vcpu_put(), but assumes * vcpu mutex is already taken. */ -static struct kvm_vcpu *vmx_vcpu_load(struct kvm_vcpu *vcpu) +static void vmx_vcpu_load(struct kvm_vcpu *vcpu) { u64 phys_addr = __pa(vcpu->vmcs); int cpu; @@ -242,7 +242,6 @@ static struct kvm_vcpu *vmx_vcpu_load(struct kvm_vcpu *vcpu) rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ } - return vcpu; } static void vmx_vcpu_put(struct kvm_vcpu *vcpu) @@ -418,10 +417,9 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) case MSR_IA32_SYSENTER_ESP: vmcs_write32(GUEST_SYSENTER_ESP, data); break; - case MSR_IA32_TIME_STAMP_COUNTER: { + case MSR_IA32_TIME_STAMP_COUNTER: guest_write_tsc(data); break; - } default: msr = find_msr_entry(vcpu, msr_index); if (msr) { @@ -793,6 +791,9 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) */ static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0) { + if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK)) + enter_rmode(vcpu); + vcpu->rmode.active = ((cr0 & CR0_PE_MASK) == 0); update_exception_bitmap(vcpu); vmcs_writel(CR0_READ_SHADOW, cr0); @@ -1467,6 +1468,18 @@ static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } +static void +vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) +{ + /* + * Patch in the VMCALL instruction: + */ + hypercall[0] = 0x0f; + hypercall[1] = 0x01; + hypercall[2] = 0xc1; + hypercall[3] = 0xc3; +} + static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { u64 exit_qualification; @@ -1643,6 +1656,12 @@ static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) return 0; } +static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) +{ + vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP)+3); + return kvm_hypercall(vcpu, kvm_run); +} + /* * The exit handlers return 1 if the exit was handled fully and guest execution * may resume. Otherwise they set the kvm_run parameter to indicate what needs @@ -1661,6 +1680,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu, [EXIT_REASON_MSR_WRITE] = handle_wrmsr, [EXIT_REASON_PENDING_INTERRUPT] = handle_interrupt_window, [EXIT_REASON_HLT] = handle_halt, + [EXIT_REASON_VMCALL] = handle_vmcall, }; static const int kvm_vmx_max_exit_handlers = @@ -2062,6 +2082,7 @@ static struct kvm_arch_ops vmx_arch_ops = { .run = vmx_vcpu_run, .skip_emulated_instruction = skip_emulated_instruction, .vcpu_setup = vmx_vcpu_setup, + .patch_hypercall = vmx_patch_hypercall, }; static int __init vmx_init(void) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 7399ba79111..80acd08f0e9 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -82,6 +82,18 @@ config LEDS_WRAP help This option enables support for the PCEngines WRAP programmable LEDs. +config LEDS_H1940 + tristate "LED Support for iPAQ H1940 device" + depends LEDS_CLASS && ARCH_H1940 + help + This option enables support for the LEDs on the h1940. + +config LEDS_COBALT + tristate "LED Support for Cobalt Server front LED" + depends on LEDS_CLASS && MIPS_COBALT + help + This option enables support for the front LED on Cobalt Server + comment "LED Triggers" config LEDS_TRIGGERS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 500de3dc962..aa2c18efa5b 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -14,6 +14,8 @@ obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o +obj-$(CONFIG_LEDS_H1940) += leds-h1940.o +obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o # LED Triggers obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o diff --git a/drivers/leds/leds-cobalt.c b/drivers/leds/leds-cobalt.c new file mode 100644 index 00000000000..d16439ce5da --- /dev/null +++ b/drivers/leds/leds-cobalt.c @@ -0,0 +1,43 @@ +/* + * Copyright 2006 - Florian Fainelli <florian@openwrt.org> + * + * Control the Cobalt Qube/RaQ front LED + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/leds.h> +#include <asm/mach-cobalt/cobalt.h> + +static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness) +{ + if (brightness) + COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT; + else + COBALT_LED_PORT = 0; +} + +static struct led_classdev cobalt_led = { + .name = "cobalt-front-led", + .brightness_set = cobalt_led_set, + .default_trigger = "ide-disk", +}; + +static int __init cobalt_led_init(void) +{ + return led_classdev_register(NULL, &cobalt_led); +} + +static void __exit cobalt_led_exit(void) +{ + led_classdev_unregister(&cobalt_led); +} + +module_init(cobalt_led_init); +module_exit(cobalt_led_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Front LED support for Cobalt Server"); +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c new file mode 100644 index 00000000000..1d49d2ade55 --- /dev/null +++ b/drivers/leds/leds-h1940.c @@ -0,0 +1,163 @@ +/* + * drivers/leds/h1940-leds.c + * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * H1940 leds driver + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/leds.h> +#include <asm/arch/regs-gpio.h> +#include <asm/hardware.h> +#include <asm/arch/h1940-latch.h> + +/* + * Green led. + */ +void h1940_greenled_set(struct led_classdev *led_dev, enum led_brightness value) +{ + switch (value) { + case LED_HALF: + h1940_latch_control(0,H1940_LATCH_LED_FLASH); + s3c2410_gpio_setpin(S3C2410_GPA7,1); + break; + case LED_FULL: + h1940_latch_control(0,H1940_LATCH_LED_GREEN); + s3c2410_gpio_setpin(S3C2410_GPA7,1); + break; + default: + case LED_OFF: + h1940_latch_control(H1940_LATCH_LED_FLASH,0); + h1940_latch_control(H1940_LATCH_LED_GREEN,0); + s3c2410_gpio_setpin(S3C2410_GPA7,0); + break; + } +} + +static struct led_classdev h1940_greenled = { + .name = "h1940:green", + .brightness_set = h1940_greenled_set, + .default_trigger = "h1940-charger", +}; + +/* + * Red led. + */ +void h1940_redled_set(struct led_classdev *led_dev, enum led_brightness value) +{ + switch (value) { + case LED_HALF: + h1940_latch_control(0,H1940_LATCH_LED_FLASH); + s3c2410_gpio_setpin(S3C2410_GPA1,1); + break; + case LED_FULL: + h1940_latch_control(0,H1940_LATCH_LED_RED); + s3c2410_gpio_setpin(S3C2410_GPA1,1); + break; + default: + case LED_OFF: + h1940_latch_control(H1940_LATCH_LED_FLASH,0); + h1940_latch_control(H1940_LATCH_LED_RED,0); + s3c2410_gpio_setpin(S3C2410_GPA1,0); + break; + } +} + +static struct led_classdev h1940_redled = { + .name = "h1940:red", + .brightness_set = h1940_redled_set, + .default_trigger = "h1940-charger", +}; + +/* + * Blue led. + * (it can only be blue flashing led) + */ +void h1940_blueled_set(struct led_classdev *led_dev, enum led_brightness value) +{ + if (value) { + /* flashing Blue */ + h1940_latch_control(0,H1940_LATCH_LED_FLASH); + s3c2410_gpio_setpin(S3C2410_GPA3,1); + } else { + h1940_latch_control(H1940_LATCH_LED_FLASH,0); + s3c2410_gpio_setpin(S3C2410_GPA3,0); + } + +} + +static struct led_classdev h1940_blueled = { + .name = "h1940:blue", + .brightness_set = h1940_blueled_set, + .default_trigger = "h1940-bluetooth", +}; + +static int __init h1940leds_probe(struct platform_device *pdev) +{ + int ret; + + ret = led_classdev_register(&pdev->dev, &h1940_greenled); + if (ret) + goto err_green; + + ret = led_classdev_register(&pdev->dev, &h1940_redled); + if (ret) + goto err_red; + + ret = led_classdev_register(&pdev->dev, &h1940_blueled); + if (ret) + goto err_blue; + + return 0; + +err_blue: + led_classdev_unregister(&h1940_redled); +err_red: + led_classdev_unregister(&h1940_greenled); +err_green: + return ret; +} + +static int h1940leds_remove(struct platform_device *pdev) +{ + led_classdev_unregister(&h1940_greenled); + led_classdev_unregister(&h1940_redled); + led_classdev_unregister(&h1940_blueled); + return 0; +} + + +static struct platform_driver h1940leds_driver = { + .driver = { + .name = "h1940-leds", + }, + .probe = h1940leds_probe, + .remove = h1940leds_remove, +}; + + +static int __init h1940leds_init(void) +{ + return platform_driver_register(&h1940leds_driver); +} + +static void __exit h1940leds_exit(void) +{ + platform_driver_unregister(&h1940leds_driver); +} + +module_init(h1940leds_init); +module_exit(h1940leds_exit); + +MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); +MODULE_DESCRIPTION("LED driver for the iPAQ H1940"); +MODULE_LICENSE("GPL"); diff --git a/drivers/md/md.c b/drivers/md/md.c index 05febfd9f07..6c06e825cff 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1296,27 +1296,17 @@ static struct super_type super_types[] = { .sync_super = super_1_sync, }, }; - -static mdk_rdev_t * match_dev_unit(mddev_t *mddev, mdk_rdev_t *dev) -{ - struct list_head *tmp; - mdk_rdev_t *rdev; - - ITERATE_RDEV(mddev,rdev,tmp) - if (rdev->bdev->bd_contains == dev->bdev->bd_contains) - return rdev; - - return NULL; -} static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) { - struct list_head *tmp; - mdk_rdev_t *rdev; + struct list_head *tmp, *tmp2; + mdk_rdev_t *rdev, *rdev2; ITERATE_RDEV(mddev1,rdev,tmp) - if (match_dev_unit(mddev2, rdev)) - return 1; + ITERATE_RDEV(mddev2, rdev2, tmp2) + if (rdev->bdev->bd_contains == + rdev2->bdev->bd_contains) + return 1; return 0; } @@ -1325,8 +1315,7 @@ static LIST_HEAD(pending_raid_disks); static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) { - mdk_rdev_t *same_pdev; - char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; + char b[BDEVNAME_SIZE]; struct kobject *ko; char *s; @@ -1342,14 +1331,6 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) else mddev->size = rdev->size; } - same_pdev = match_dev_unit(mddev, rdev); - if (same_pdev) - printk(KERN_WARNING - "%s: WARNING: %s appears to be on the same physical" - " disk as %s. True\n protection against single-disk" - " failure might be compromised.\n", - mdname(mddev), bdevname(rdev->bdev,b), - bdevname(same_pdev->bdev,b2)); /* Verify rdev->desc_nr is unique. * If it is -1, assign a free number, else @@ -3109,6 +3090,36 @@ static int do_md_run(mddev_t * mddev) return -EINVAL; } + if (pers->sync_request) { + /* Warn if this is a potentially silly + * configuration. + */ + char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; + mdk_rdev_t *rdev2; + struct list_head *tmp2; + int warned = 0; + ITERATE_RDEV(mddev, rdev, tmp) { + ITERATE_RDEV(mddev, rdev2, tmp2) { + if (rdev < rdev2 && + rdev->bdev->bd_contains == + rdev2->bdev->bd_contains) { + printk(KERN_WARNING + "%s: WARNING: %s appears to be" + " on the same physical disk as" + " %s.\n", + mdname(mddev), + bdevname(rdev->bdev,b), + bdevname(rdev2->bdev,b2)); + warned = 1; + } + } + } + if (warned) + printk(KERN_WARNING + "True protection against single-disk" + " failure might be compromised.\n"); + } + mddev->recovery = 0; mddev->resync_max_sectors = mddev->size << 1; /* may be over-ridden by personality */ mddev->barriers_work = 1; @@ -3311,6 +3322,9 @@ static int do_md_stop(mddev_t * mddev, int mode) set_disk_ro(disk, 0); blk_queue_make_request(mddev->queue, md_fail_request); mddev->pers->stop(mddev); + mddev->queue->merge_bvec_fn = NULL; + mddev->queue->unplug_fn = NULL; + mddev->queue->issue_flush_fn = NULL; if (mddev->pers->sync_request) sysfs_remove_group(&mddev->kobj, &md_redundancy_group); @@ -5343,6 +5357,44 @@ void md_do_sync(mddev_t *mddev) EXPORT_SYMBOL_GPL(md_do_sync); +static int remove_and_add_spares(mddev_t *mddev) +{ + mdk_rdev_t *rdev; + struct list_head *rtmp; + int spares = 0; + + ITERATE_RDEV(mddev,rdev,rtmp) + if (rdev->raid_disk >= 0 && + (test_bit(Faulty, &rdev->flags) || + ! test_bit(In_sync, &rdev->flags)) && + atomic_read(&rdev->nr_pending)==0) { + if (mddev->pers->hot_remove_disk( + mddev, rdev->raid_disk)==0) { + char nm[20]; + sprintf(nm,"rd%d", rdev->raid_disk); + sysfs_remove_link(&mddev->kobj, nm); + rdev->raid_disk = -1; + } + } + + if (mddev->degraded) { + ITERATE_RDEV(mddev,rdev,rtmp) + if (rdev->raid_disk < 0 + && !test_bit(Faulty, &rdev->flags)) { + rdev->recovery_offset = 0; + if (mddev->pers->hot_add_disk(mddev,rdev)) { + char nm[20]; + sprintf(nm, "rd%d", rdev->raid_disk); + sysfs_create_link(&mddev->kobj, + &rdev->kobj, nm); + spares++; + md_new_event(mddev); + } else + break; + } + } + return spares; +} /* * This routine is regularly called by all per-raid-array threads to * deal with generic issues like resync and super-block update. @@ -5397,7 +5449,7 @@ void md_check_recovery(mddev_t *mddev) return; if (mddev_trylock(mddev)) { - int spares =0; + int spares = 0; spin_lock_irq(&mddev->write_lock); if (mddev->safemode && !atomic_read(&mddev->writes_pending) && @@ -5460,35 +5512,13 @@ void md_check_recovery(mddev_t *mddev) * Spare are also removed and re-added, to allow * the personality to fail the re-add. */ - ITERATE_RDEV(mddev,rdev,rtmp) - if (rdev->raid_disk >= 0 && - (test_bit(Faulty, &rdev->flags) || ! test_bit(In_sync, &rdev->flags)) && - atomic_read(&rdev->nr_pending)==0) { - if (mddev->pers->hot_remove_disk(mddev, rdev->raid_disk)==0) { - char nm[20]; - sprintf(nm,"rd%d", rdev->raid_disk); - sysfs_remove_link(&mddev->kobj, nm); - rdev->raid_disk = -1; - } - } - - if (mddev->degraded) { - ITERATE_RDEV(mddev,rdev,rtmp) - if (rdev->raid_disk < 0 - && !test_bit(Faulty, &rdev->flags)) { - rdev->recovery_offset = 0; - if (mddev->pers->hot_add_disk(mddev,rdev)) { - char nm[20]; - sprintf(nm, "rd%d", rdev->raid_disk); - sysfs_create_link(&mddev->kobj, &rdev->kobj, nm); - spares++; - md_new_event(mddev); - } else - break; - } - } - if (spares) { + if (mddev->reshape_position != MaxSector) { + if (mddev->pers->check_reshape(mddev) != 0) + /* Cannot proceed */ + goto unlock; + set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery); + } else if ((spares = remove_and_add_spares(mddev))) { clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); } else if (mddev->recovery_cp < MaxSector) { diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index a9401c017e3..82249a69014 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -429,7 +429,7 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev) if (dev < 0) dev += conf->raid_disks; } else { - while (sector > conf->stride) { + while (sector >= conf->stride) { sector -= conf->stride; if (dev < conf->near_copies) dev += conf->raid_disks - conf->near_copies; @@ -1801,6 +1801,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i for (k=0; k<conf->copies; k++) if (r10_bio->devs[k].devnum == i) break; + BUG_ON(k == conf->copies); bio = r10_bio->devs[1].bio; bio->bi_next = biolist; biolist = bio; @@ -2021,19 +2022,30 @@ static int run(mddev_t *mddev) if (!conf->tmppage) goto out_free_conf; + conf->mddev = mddev; + conf->raid_disks = mddev->raid_disks; conf->near_copies = nc; conf->far_copies = fc; conf->copies = nc*fc; conf->far_offset = fo; conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1; conf->chunk_shift = ffz(~mddev->chunk_size) - 9; + size = mddev->size >> (conf->chunk_shift-1); + sector_div(size, fc); + size = size * conf->raid_disks; + sector_div(size, nc); + /* 'size' is now the number of chunks in the array */ + /* calculate "used chunks per device" in 'stride' */ + stride = size * conf->copies; + sector_div(stride, conf->raid_disks); + mddev->size = stride << (conf->chunk_shift-1); + if (fo) - conf->stride = 1 << conf->chunk_shift; - else { - stride = mddev->size >> (conf->chunk_shift-1); + stride = 1; + else sector_div(stride, fc); - conf->stride = stride << conf->chunk_shift; - } + conf->stride = stride << conf->chunk_shift; + conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc, r10bio_pool_free, conf); if (!conf->r10bio_pool) { @@ -2063,8 +2075,6 @@ static int run(mddev_t *mddev) disk->head_position = 0; } - conf->raid_disks = mddev->raid_disks; - conf->mddev = mddev; spin_lock_init(&conf->device_lock); INIT_LIST_HEAD(&conf->retry_list); @@ -2106,16 +2116,8 @@ static int run(mddev_t *mddev) /* * Ok, everything is just fine now */ - if (conf->far_offset) { - size = mddev->size >> (conf->chunk_shift-1); - size *= conf->raid_disks; - size <<= conf->chunk_shift; - sector_div(size, conf->far_copies); - } else - size = conf->stride * conf->raid_disks; - sector_div(size, conf->near_copies); - mddev->array_size = size/2; - mddev->resync_max_sectors = size; + mddev->array_size = size << (conf->chunk_shift-1); + mddev->resync_max_sectors = size << conf->chunk_shift; mddev->queue->unplug_fn = raid10_unplug; mddev->queue->issue_flush_fn = raid10_issue_flush; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 11c3d7bfa79..54a1ad5eef4 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1050,7 +1050,7 @@ static void compute_parity5(struct stripe_head *sh, int method) static void compute_parity6(struct stripe_head *sh, int method) { raid6_conf_t *conf = sh->raid_conf; - int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count; + int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = sh->disks, count; struct bio *chosen; /**** FIX THIS: This could be very bad if disks is close to 256 ****/ void *ptrs[disks]; @@ -1131,8 +1131,7 @@ static void compute_parity6(struct stripe_head *sh, int method) /* Compute one missing block */ static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero) { - raid6_conf_t *conf = sh->raid_conf; - int i, count, disks = conf->raid_disks; + int i, count, disks = sh->disks; void *ptr[MAX_XOR_BLOCKS], *p; int pd_idx = sh->pd_idx; int qd_idx = raid6_next_disk(pd_idx, disks); @@ -1170,8 +1169,7 @@ static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero) /* Compute two missing blocks */ static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2) { - raid6_conf_t *conf = sh->raid_conf; - int i, count, disks = conf->raid_disks; + int i, count, disks = sh->disks; int pd_idx = sh->pd_idx; int qd_idx = raid6_next_disk(pd_idx, disks); int d0_idx = raid6_next_disk(qd_idx, disks); @@ -1887,11 +1885,11 @@ static void handle_stripe5(struct stripe_head *sh) static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) { raid6_conf_t *conf = sh->raid_conf; - int disks = conf->raid_disks; + int disks = sh->disks; struct bio *return_bi= NULL; struct bio *bi; int i; - int syncing; + int syncing, expanding, expanded; int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0; int non_overwrite = 0; int failed_num[2] = {0, 0}; @@ -1909,6 +1907,8 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) clear_bit(STRIPE_DELAYED, &sh->state); syncing = test_bit(STRIPE_SYNCING, &sh->state); + expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state); + expanded = test_bit(STRIPE_EXPAND_READY, &sh->state); /* Now to look around and see what can be done */ rcu_read_lock(); @@ -2114,13 +2114,15 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) * parity, or to satisfy requests * or to load a block that is being partially written. */ - if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) { + if (to_read || non_overwrite || (to_write && failed) || + (syncing && (uptodate < disks)) || expanding) { for (i=disks; i--;) { dev = &sh->dev[i]; if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) && (dev->toread || (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) || syncing || + expanding || (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) || (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write)) ) @@ -2355,6 +2357,79 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) } } } + + if (expanded && test_bit(STRIPE_EXPANDING, &sh->state)) { + /* Need to write out all blocks after computing P&Q */ + sh->disks = conf->raid_disks; + sh->pd_idx = stripe_to_pdidx(sh->sector, conf, + conf->raid_disks); + compute_parity6(sh, RECONSTRUCT_WRITE); + for (i = conf->raid_disks ; i-- ; ) { + set_bit(R5_LOCKED, &sh->dev[i].flags); + locked++; + set_bit(R5_Wantwrite, &sh->dev[i].flags); + } + clear_bit(STRIPE_EXPANDING, &sh->state); + } else if (expanded) { + clear_bit(STRIPE_EXPAND_READY, &sh->state); + atomic_dec(&conf->reshape_stripes); + wake_up(&conf->wait_for_overlap); + md_done_sync(conf->mddev, STRIPE_SECTORS, 1); + } + + if (expanding && locked == 0) { + /* We have read all the blocks in this stripe and now we need to + * copy some of them into a target stripe for expand. + */ + clear_bit(STRIPE_EXPAND_SOURCE, &sh->state); + for (i = 0; i < sh->disks ; i++) + if (i != pd_idx && i != qd_idx) { + int dd_idx2, pd_idx2, j; + struct stripe_head *sh2; + + sector_t bn = compute_blocknr(sh, i); + sector_t s = raid5_compute_sector( + bn, conf->raid_disks, + conf->raid_disks - conf->max_degraded, + &dd_idx2, &pd_idx2, conf); + sh2 = get_active_stripe(conf, s, + conf->raid_disks, + pd_idx2, 1); + if (sh2 == NULL) + /* so for only the early blocks of + * this stripe have been requests. + * When later blocks get requests, we + * will try again + */ + continue; + if (!test_bit(STRIPE_EXPANDING, &sh2->state) || + test_bit(R5_Expanded, + &sh2->dev[dd_idx2].flags)) { + /* must have already done this block */ + release_stripe(sh2); + continue; + } + memcpy(page_address(sh2->dev[dd_idx2].page), + page_address(sh->dev[i].page), + STRIPE_SIZE); + set_bit(R5_Expanded, &sh2->dev[dd_idx2].flags); + set_bit(R5_UPTODATE, &sh2->dev[dd_idx2].flags); + for (j = 0 ; j < conf->raid_disks ; j++) + if (j != sh2->pd_idx && + j != raid6_next_disk(sh2->pd_idx, + sh2->disks) && + !test_bit(R5_Expanded, + &sh2->dev[j].flags)) + break; + if (j == conf->raid_disks) { + set_bit(STRIPE_EXPAND_READY, + &sh2->state); + set_bit(STRIPE_HANDLE, &sh2->state); + } + release_stripe(sh2); + } + } + spin_unlock(&sh->lock); while ((bi=return_bi)) { @@ -2395,7 +2470,7 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) rcu_read_unlock(); if (rdev) { - if (syncing) + if (syncing || expanding || expanded) md_sync_acct(rdev->bdev, STRIPE_SECTORS); bi->bi_bdev = rdev->bdev; @@ -2915,8 +2990,9 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped struct stripe_head *sh; int pd_idx; sector_t first_sector, last_sector; - int raid_disks; - int data_disks; + int raid_disks = conf->previous_raid_disks; + int data_disks = raid_disks - conf->max_degraded; + int new_data_disks = conf->raid_disks - conf->max_degraded; int i; int dd_idx; sector_t writepos, safepos, gap; @@ -2925,7 +3001,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped conf->expand_progress != 0) { /* restarting in the middle, skip the initial sectors */ sector_nr = conf->expand_progress; - sector_div(sector_nr, conf->raid_disks-1); + sector_div(sector_nr, new_data_disks); *skipped = 1; return sector_nr; } @@ -2939,14 +3015,14 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped * to after where expand_lo old_maps to */ writepos = conf->expand_progress + - conf->chunk_size/512*(conf->raid_disks-1); - sector_div(writepos, conf->raid_disks-1); + conf->chunk_size/512*(new_data_disks); + sector_div(writepos, new_data_disks); safepos = conf->expand_lo; - sector_div(safepos, conf->previous_raid_disks-1); + sector_div(safepos, data_disks); gap = conf->expand_progress - conf->expand_lo; if (writepos >= safepos || - gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) { + gap > (new_data_disks)*3000*2 /*3Meg*/) { /* Cannot proceed until we've updated the superblock... */ wait_event(conf->wait_for_overlap, atomic_read(&conf->reshape_stripes)==0); @@ -2976,6 +3052,9 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped sector_t s; if (j == sh->pd_idx) continue; + if (conf->level == 6 && + j == raid6_next_disk(sh->pd_idx, sh->disks)) + continue; s = compute_blocknr(sh, j); if (s < (mddev->array_size<<1)) { skipped = 1; @@ -2992,28 +3071,27 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped release_stripe(sh); } spin_lock_irq(&conf->device_lock); - conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1); + conf->expand_progress = (sector_nr + i) * new_data_disks; spin_unlock_irq(&conf->device_lock); /* Ok, those stripe are ready. We can start scheduling * reads on the source stripes. * The source stripes are determined by mapping the first and last * block on the destination stripes. */ - raid_disks = conf->previous_raid_disks; - data_disks = raid_disks - 1; first_sector = - raid5_compute_sector(sector_nr*(conf->raid_disks-1), + raid5_compute_sector(sector_nr*(new_data_disks), raid_disks, data_disks, &dd_idx, &pd_idx, conf); last_sector = raid5_compute_sector((sector_nr+conf->chunk_size/512) - *(conf->raid_disks-1) -1, + *(new_data_disks) -1, raid_disks, data_disks, &dd_idx, &pd_idx, conf); if (last_sector >= (mddev->size<<1)) last_sector = (mddev->size<<1)-1; while (first_sector <= last_sector) { - pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks); + pd_idx = stripe_to_pdidx(first_sector, conf, + conf->previous_raid_disks); sh = get_active_stripe(conf, first_sector, conf->previous_raid_disks, pd_idx, 0); set_bit(STRIPE_EXPAND_SOURCE, &sh->state); @@ -3348,35 +3426,44 @@ static int run(mddev_t *mddev) */ sector_t here_new, here_old; int old_disks; + int max_degraded = (mddev->level == 5 ? 1 : 2); if (mddev->new_level != mddev->level || mddev->new_layout != mddev->layout || mddev->new_chunk != mddev->chunk_size) { - printk(KERN_ERR "raid5: %s: unsupported reshape required - aborting.\n", + printk(KERN_ERR "raid5: %s: unsupported reshape " + "required - aborting.\n", mdname(mddev)); return -EINVAL; } if (mddev->delta_disks <= 0) { - printk(KERN_ERR "raid5: %s: unsupported reshape (reduce disks) required - aborting.\n", + printk(KERN_ERR "raid5: %s: unsupported reshape " + "(reduce disks) required - aborting.\n", mdname(mddev)); return -EINVAL; } old_disks = mddev->raid_disks - mddev->delta_disks; /* reshape_position must be on a new-stripe boundary, and one - * further up in new geometry must map after here in old geometry. + * further up in new geometry must map after here in old + * geometry. */ here_new = mddev->reshape_position; - if (sector_div(here_new, (mddev->chunk_size>>9)*(mddev->raid_disks-1))) { - printk(KERN_ERR "raid5: reshape_position not on a stripe boundary\n"); + if (sector_div(here_new, (mddev->chunk_size>>9)* + (mddev->raid_disks - max_degraded))) { + printk(KERN_ERR "raid5: reshape_position not " + "on a stripe boundary\n"); return -EINVAL; } /* here_new is the stripe we will write to */ here_old = mddev->reshape_position; - sector_div(here_old, (mddev->chunk_size>>9)*(old_disks-1)); - /* here_old is the first stripe that we might need to read from */ + sector_div(here_old, (mddev->chunk_size>>9)* + (old_disks-max_degraded)); + /* here_old is the first stripe that we might need to read + * from */ if (here_new >= here_old) { /* Reading from the same stripe as writing to - bad */ - printk(KERN_ERR "raid5: reshape_position too early for auto-recovery - aborting.\n"); + printk(KERN_ERR "raid5: reshape_position too early for " + "auto-recovery - aborting.\n"); return -EINVAL; } printk(KERN_INFO "raid5: reshape will continue\n"); @@ -3814,6 +3901,8 @@ static int raid5_check_reshape(mddev_t *mddev) if (err) return err; + if (mddev->degraded > conf->max_degraded) + return -EINVAL; /* looks like we might be able to manage this */ return 0; } @@ -3827,8 +3916,7 @@ static int raid5_start_reshape(mddev_t *mddev) int added_devices = 0; unsigned long flags; - if (mddev->degraded || - test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) + if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) return -EBUSY; ITERATE_RDEV(mddev, rdev, rtmp) @@ -3836,7 +3924,7 @@ static int raid5_start_reshape(mddev_t *mddev) !test_bit(Faulty, &rdev->flags)) spares++; - if (spares < mddev->delta_disks-1) + if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded) /* Not enough devices even to make a degraded array * of that size */ @@ -3899,7 +3987,8 @@ static void end_reshape(raid5_conf_t *conf) struct block_device *bdev; if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { - conf->mddev->array_size = conf->mddev->size * (conf->raid_disks-1); + conf->mddev->array_size = conf->mddev->size * + (conf->raid_disks - conf->max_degraded); set_capacity(conf->mddev->gendisk, conf->mddev->array_size << 1); conf->mddev->changed = 1; @@ -3972,6 +4061,10 @@ static struct mdk_personality raid6_personality = .spare_active = raid5_spare_active, .sync_request = sync_request, .resize = raid5_resize, +#ifdef CONFIG_MD_RAID5_RESHAPE + .check_reshape = raid5_check_reshape, + .start_reshape = raid5_start_reshape, +#endif .quiesce = raid5_quiesce, }; static struct mdk_personality raid5_personality = diff --git a/drivers/md/raid6mmx.c b/drivers/md/raid6mmx.c index 359157aaf9e..6181a5a3365 100644 --- a/drivers/md/raid6mmx.c +++ b/drivers/md/raid6mmx.c @@ -30,14 +30,8 @@ const struct raid6_mmx_constants { static int raid6_have_mmx(void) { -#ifdef __KERNEL__ /* Not really "boot_cpu" but "all_cpus" */ return boot_cpu_has(X86_FEATURE_MMX); -#else - /* User space test code */ - u32 features = cpuid_features(); - return ( (features & (1<<23)) == (1<<23) ); -#endif } /* @@ -48,13 +42,12 @@ static void raid6_mmx1_gen_syndrome(int disks, size_t bytes, void **ptrs) u8 **dptr = (u8 **)ptrs; u8 *p, *q; int d, z, z0; - raid6_mmx_save_t sa; z0 = disks - 3; /* Highest data disk */ p = dptr[z0+1]; /* XOR parity */ q = dptr[z0+2]; /* RS syndrome */ - raid6_before_mmx(&sa); + kernel_fpu_begin(); asm volatile("movq %0,%%mm0" : : "m" (raid6_mmx_constants.x1d)); asm volatile("pxor %mm5,%mm5"); /* Zero temp */ @@ -78,7 +71,7 @@ static void raid6_mmx1_gen_syndrome(int disks, size_t bytes, void **ptrs) asm volatile("pxor %mm4,%mm4"); } - raid6_after_mmx(&sa); + kernel_fpu_end(); } const struct raid6_calls raid6_mmxx1 = { @@ -96,13 +89,12 @@ static void raid6_mmx2_gen_syndrome(int disks, size_t bytes, void **ptrs) u8 **dptr = (u8 **)ptrs; u8 *p, *q; int d, z, z0; - raid6_mmx_save_t sa; z0 = disks - 3; /* Highest data disk */ p = dptr[z0+1]; /* XOR parity */ q = dptr[z0+2]; /* RS syndrome */ - raid6_before_mmx(&sa); + kernel_fpu_begin(); asm volatile("movq %0,%%mm0" : : "m" (raid6_mmx_constants.x1d)); asm volatile("pxor %mm5,%mm5"); /* Zero temp */ @@ -137,7 +129,7 @@ static void raid6_mmx2_gen_syndrome(int disks, size_t bytes, void **ptrs) asm volatile("movq %%mm6,%0" : "=m" (q[d+8])); } - raid6_after_mmx(&sa); + kernel_fpu_end(); } const struct raid6_calls raid6_mmxx2 = { diff --git a/drivers/md/raid6sse1.c b/drivers/md/raid6sse1.c index f7e7859f71a..f0a1ba8f40b 100644 --- a/drivers/md/raid6sse1.c +++ b/drivers/md/raid6sse1.c @@ -33,16 +33,10 @@ extern const struct raid6_mmx_constants { static int raid6_have_sse1_or_mmxext(void) { -#ifdef __KERNEL__ /* Not really boot_cpu but "all_cpus" */ return boot_cpu_has(X86_FEATURE_MMX) && (boot_cpu_has(X86_FEATURE_XMM) || boot_cpu_has(X86_FEATURE_MMXEXT)); -#else - /* User space test code - this incorrectly breaks on some Athlons */ - u32 features = cpuid_features(); - return ( (features & (5<<23)) == (5<<23) ); -#endif } /* @@ -53,14 +47,12 @@ static void raid6_sse11_gen_syndrome(int disks, size_t bytes, void **ptrs) u8 **dptr = (u8 **)ptrs; u8 *p, *q; int d, z, z0; - raid6_mmx_save_t sa; z0 = disks - 3; /* Highest data disk */ p = dptr[z0+1]; /* XOR parity */ q = dptr[z0+2]; /* RS syndrome */ - /* This is really MMX code, not SSE */ - raid6_before_mmx(&sa); + kernel_fpu_begin(); asm volatile("movq %0,%%mm0" : : "m" (raid6_mmx_constants.x1d)); asm volatile("pxor %mm5,%mm5"); /* Zero temp */ @@ -94,8 +86,8 @@ static void raid6_sse11_gen_syndrome(int disks, size_t bytes, void **ptrs) asm volatile("movntq %%mm4,%0" : "=m" (q[d])); } - raid6_after_mmx(&sa); asm volatile("sfence" : : : "memory"); + kernel_fpu_end(); } const struct raid6_calls raid6_sse1x1 = { @@ -113,13 +105,12 @@ static void raid6_sse12_gen_syndrome(int disks, size_t bytes, void **ptrs) u8 **dptr = (u8 **)ptrs; u8 *p, *q; int d, z, z0; - raid6_mmx_save_t sa; z0 = disks - 3; /* Highest data disk */ p = dptr[z0+1]; /* XOR parity */ q = dptr[z0+2]; /* RS syndrome */ - raid6_before_mmx(&sa); + kernel_fpu_begin(); asm volatile("movq %0,%%mm0" : : "m" (raid6_mmx_constants.x1d)); asm volatile("pxor %mm5,%mm5"); /* Zero temp */ @@ -157,8 +148,8 @@ static void raid6_sse12_gen_syndrome(int disks, size_t bytes, void **ptrs) asm volatile("movntq %%mm6,%0" : "=m" (q[d+8])); } - raid6_after_mmx(&sa); asm volatile("sfence" : :: "memory"); + kernel_fpu_end(); } const struct raid6_calls raid6_sse1x2 = { diff --git a/drivers/md/raid6sse2.c b/drivers/md/raid6sse2.c index b3aa7fe0877..0f019762a7c 100644 --- a/drivers/md/raid6sse2.c +++ b/drivers/md/raid6sse2.c @@ -30,17 +30,11 @@ static const struct raid6_sse_constants { static int raid6_have_sse2(void) { -#ifdef __KERNEL__ /* Not really boot_cpu but "all_cpus" */ return boot_cpu_has(X86_FEATURE_MMX) && boot_cpu_has(X86_FEATURE_FXSR) && boot_cpu_has(X86_FEATURE_XMM) && boot_cpu_has(X86_FEATURE_XMM2); -#else - /* User space test code */ - u32 features = cpuid_features(); - return ( (features & (15<<23)) == (15<<23) ); -#endif } /* @@ -51,13 +45,12 @@ static void raid6_sse21_gen_syndrome(int disks, size_t bytes, void **ptrs) u8 **dptr = (u8 **)ptrs; u8 *p, *q; int d, z, z0; - raid6_sse_save_t sa; z0 = disks - 3; /* Highest data disk */ p = dptr[z0+1]; /* XOR parity */ q = dptr[z0+2]; /* RS syndrome */ - raid6_before_sse2(&sa); + kernel_fpu_begin(); asm volatile("movdqa %0,%%xmm0" : : "m" (raid6_sse_constants.x1d[0])); asm volatile("pxor %xmm5,%xmm5"); /* Zero temp */ @@ -93,8 +86,8 @@ static void raid6_sse21_gen_syndrome(int disks, size_t bytes, void **ptrs) asm volatile("pxor %xmm4,%xmm4"); } - raid6_after_sse2(&sa); asm volatile("sfence" : : : "memory"); + kernel_fpu_end(); } const struct raid6_calls raid6_sse2x1 = { @@ -112,13 +105,12 @@ static void raid6_sse22_gen_syndrome(int disks, size_t bytes, void **ptrs) u8 **dptr = (u8 **)ptrs; u8 *p, *q; int d, z, z0; - raid6_sse_save_t sa; z0 = disks - 3; /* Highest data disk */ p = dptr[z0+1]; /* XOR parity */ q = dptr[z0+2]; /* RS syndrome */ - raid6_before_sse2(&sa); + kernel_fpu_begin(); asm volatile("movdqa %0,%%xmm0" : : "m" (raid6_sse_constants.x1d[0])); asm volatile("pxor %xmm5,%xmm5"); /* Zero temp */ @@ -156,8 +148,8 @@ static void raid6_sse22_gen_syndrome(int disks, size_t bytes, void **ptrs) asm volatile("movntdq %%xmm6,%0" : "=m" (q[d+16])); } - raid6_after_sse2(&sa); asm volatile("sfence" : : : "memory"); + kernel_fpu_end(); } const struct raid6_calls raid6_sse2x2 = { @@ -179,13 +171,12 @@ static void raid6_sse24_gen_syndrome(int disks, size_t bytes, void **ptrs) u8 **dptr = (u8 **)ptrs; u8 *p, *q; int d, z, z0; - raid6_sse16_save_t sa; z0 = disks - 3; /* Highest data disk */ p = dptr[z0+1]; /* XOR parity */ q = dptr[z0+2]; /* RS syndrome */ - raid6_before_sse16(&sa); + kernel_fpu_begin(); asm volatile("movdqa %0,%%xmm0" :: "m" (raid6_sse_constants.x1d[0])); asm volatile("pxor %xmm2,%xmm2"); /* P[0] */ @@ -256,8 +247,9 @@ static void raid6_sse24_gen_syndrome(int disks, size_t bytes, void **ptrs) asm volatile("movntdq %%xmm14,%0" : "=m" (q[d+48])); asm volatile("pxor %xmm14,%xmm14"); } + asm volatile("sfence" : : : "memory"); - raid6_after_sse16(&sa); + kernel_fpu_end(); } const struct raid6_calls raid6_sse2x4 = { diff --git a/drivers/md/raid6x86.h b/drivers/md/raid6x86.h index 4cf20534fe4..9111950414f 100644 --- a/drivers/md/raid6x86.h +++ b/drivers/md/raid6x86.h @@ -21,224 +21,40 @@ #if defined(__i386__) || defined(__x86_64__) -#ifdef __x86_64__ - -typedef struct { - unsigned int fsave[27]; - unsigned long cr0; -} raid6_mmx_save_t __attribute__((aligned(16))); - -/* N.B.: For SSE we only save %xmm0-%xmm7 even for x86-64, since - the code doesn't know about the additional x86-64 registers */ -typedef struct { - unsigned int sarea[8*4+2]; - unsigned long cr0; -} raid6_sse_save_t __attribute__((aligned(16))); - -/* This is for x86-64-specific code which uses all 16 XMM registers */ -typedef struct { - unsigned int sarea[16*4+2]; - unsigned long cr0; -} raid6_sse16_save_t __attribute__((aligned(16))); - -/* On x86-64 the stack *SHOULD* be 16-byte aligned, but currently this - is buggy in the kernel and it's only 8-byte aligned in places, so - we need to do this anyway. Sigh. */ -#define SAREA(x) ((unsigned int *)((((unsigned long)&(x)->sarea)+15) & ~15)) - -#else /* __i386__ */ - -typedef struct { - unsigned int fsave[27]; - unsigned long cr0; -} raid6_mmx_save_t; - -/* On i386, the stack is only 8-byte aligned, but SSE requires 16-byte - alignment. The +3 is so we have the slack space to manually align - a properly-sized area correctly. */ -typedef struct { - unsigned int sarea[8*4+3]; - unsigned long cr0; -} raid6_sse_save_t; - -/* Find the 16-byte aligned save area */ -#define SAREA(x) ((unsigned int *)((((unsigned long)&(x)->sarea)+15) & ~15)) - -#endif - #ifdef __KERNEL__ /* Real code */ -/* Note: %cr0 is 32 bits on i386 and 64 bits on x86-64 */ - -static inline unsigned long raid6_get_fpu(void) -{ - unsigned long cr0; - - preempt_disable(); - asm volatile("mov %%cr0,%0 ; clts" : "=r" (cr0)); - return cr0; -} - -static inline void raid6_put_fpu(unsigned long cr0) -{ - asm volatile("mov %0,%%cr0" : : "r" (cr0)); - preempt_enable(); -} +#include <asm/i387.h> #else /* Dummy code for user space testing */ -static inline unsigned long raid6_get_fpu(void) -{ - return 0xf00ba6; -} - -static inline void raid6_put_fpu(unsigned long cr0) -{ - (void)cr0; -} - -#endif - -static inline void raid6_before_mmx(raid6_mmx_save_t *s) -{ - s->cr0 = raid6_get_fpu(); - asm volatile("fsave %0 ; fwait" : "=m" (s->fsave[0])); -} - -static inline void raid6_after_mmx(raid6_mmx_save_t *s) -{ - asm volatile("frstor %0" : : "m" (s->fsave[0])); - raid6_put_fpu(s->cr0); -} - -static inline void raid6_before_sse(raid6_sse_save_t *s) -{ - unsigned int *rsa = SAREA(s); - - s->cr0 = raid6_get_fpu(); - - asm volatile("movaps %%xmm0,%0" : "=m" (rsa[0])); - asm volatile("movaps %%xmm1,%0" : "=m" (rsa[4])); - asm volatile("movaps %%xmm2,%0" : "=m" (rsa[8])); - asm volatile("movaps %%xmm3,%0" : "=m" (rsa[12])); - asm volatile("movaps %%xmm4,%0" : "=m" (rsa[16])); - asm volatile("movaps %%xmm5,%0" : "=m" (rsa[20])); - asm volatile("movaps %%xmm6,%0" : "=m" (rsa[24])); - asm volatile("movaps %%xmm7,%0" : "=m" (rsa[28])); -} - -static inline void raid6_after_sse(raid6_sse_save_t *s) -{ - unsigned int *rsa = SAREA(s); - - asm volatile("movaps %0,%%xmm0" : : "m" (rsa[0])); - asm volatile("movaps %0,%%xmm1" : : "m" (rsa[4])); - asm volatile("movaps %0,%%xmm2" : : "m" (rsa[8])); - asm volatile("movaps %0,%%xmm3" : : "m" (rsa[12])); - asm volatile("movaps %0,%%xmm4" : : "m" (rsa[16])); - asm volatile("movaps %0,%%xmm5" : : "m" (rsa[20])); - asm volatile("movaps %0,%%xmm6" : : "m" (rsa[24])); - asm volatile("movaps %0,%%xmm7" : : "m" (rsa[28])); - - raid6_put_fpu(s->cr0); -} - -static inline void raid6_before_sse2(raid6_sse_save_t *s) +static inline void kernel_fpu_begin(void) { - unsigned int *rsa = SAREA(s); - - s->cr0 = raid6_get_fpu(); - - asm volatile("movdqa %%xmm0,%0" : "=m" (rsa[0])); - asm volatile("movdqa %%xmm1,%0" : "=m" (rsa[4])); - asm volatile("movdqa %%xmm2,%0" : "=m" (rsa[8])); - asm volatile("movdqa %%xmm3,%0" : "=m" (rsa[12])); - asm volatile("movdqa %%xmm4,%0" : "=m" (rsa[16])); - asm volatile("movdqa %%xmm5,%0" : "=m" (rsa[20])); - asm volatile("movdqa %%xmm6,%0" : "=m" (rsa[24])); - asm volatile("movdqa %%xmm7,%0" : "=m" (rsa[28])); } -static inline void raid6_after_sse2(raid6_sse_save_t *s) +static inline void kernel_fpu_end(void) { - unsigned int *rsa = SAREA(s); - - asm volatile("movdqa %0,%%xmm0" : : "m" (rsa[0])); - asm volatile("movdqa %0,%%xmm1" : : "m" (rsa[4])); - asm volatile("movdqa %0,%%xmm2" : : "m" (rsa[8])); - asm volatile("movdqa %0,%%xmm3" : : "m" (rsa[12])); - asm volatile("movdqa %0,%%xmm4" : : "m" (rsa[16])); - asm volatile("movdqa %0,%%xmm5" : : "m" (rsa[20])); - asm volatile("movdqa %0,%%xmm6" : : "m" (rsa[24])); - asm volatile("movdqa %0,%%xmm7" : : "m" (rsa[28])); - - raid6_put_fpu(s->cr0); } -#ifdef __x86_64__ - -static inline void raid6_before_sse16(raid6_sse16_save_t *s) -{ - unsigned int *rsa = SAREA(s); - - s->cr0 = raid6_get_fpu(); +#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */ +#define X86_FEATURE_FXSR (0*32+24) /* FXSAVE and FXRSTOR instructions + * (fast save and restore) */ +#define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */ +#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */ +#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */ - asm volatile("movdqa %%xmm0,%0" : "=m" (rsa[0])); - asm volatile("movdqa %%xmm1,%0" : "=m" (rsa[4])); - asm volatile("movdqa %%xmm2,%0" : "=m" (rsa[8])); - asm volatile("movdqa %%xmm3,%0" : "=m" (rsa[12])); - asm volatile("movdqa %%xmm4,%0" : "=m" (rsa[16])); - asm volatile("movdqa %%xmm5,%0" : "=m" (rsa[20])); - asm volatile("movdqa %%xmm6,%0" : "=m" (rsa[24])); - asm volatile("movdqa %%xmm7,%0" : "=m" (rsa[28])); - asm volatile("movdqa %%xmm8,%0" : "=m" (rsa[32])); - asm volatile("movdqa %%xmm9,%0" : "=m" (rsa[36])); - asm volatile("movdqa %%xmm10,%0" : "=m" (rsa[40])); - asm volatile("movdqa %%xmm11,%0" : "=m" (rsa[44])); - asm volatile("movdqa %%xmm12,%0" : "=m" (rsa[48])); - asm volatile("movdqa %%xmm13,%0" : "=m" (rsa[52])); - asm volatile("movdqa %%xmm14,%0" : "=m" (rsa[56])); - asm volatile("movdqa %%xmm15,%0" : "=m" (rsa[60])); -} - -static inline void raid6_after_sse16(raid6_sse16_save_t *s) +/* Should work well enough on modern CPUs for testing */ +static inline int boot_cpu_has(int flag) { - unsigned int *rsa = SAREA(s); + u32 eax = (flag >> 5) ? 0x80000001 : 1; + u32 edx; - asm volatile("movdqa %0,%%xmm0" : : "m" (rsa[0])); - asm volatile("movdqa %0,%%xmm1" : : "m" (rsa[4])); - asm volatile("movdqa %0,%%xmm2" : : "m" (rsa[8])); - asm volatile("movdqa %0,%%xmm3" : : "m" (rsa[12])); - asm volatile("movdqa %0,%%xmm4" : : "m" (rsa[16])); - asm volatile("movdqa %0,%%xmm5" : : "m" (rsa[20])); - asm volatile("movdqa %0,%%xmm6" : : "m" (rsa[24])); - asm volatile("movdqa %0,%%xmm7" : : "m" (rsa[28])); - asm volatile("movdqa %0,%%xmm8" : : "m" (rsa[32])); - asm volatile("movdqa %0,%%xmm9" : : "m" (rsa[36])); - asm volatile("movdqa %0,%%xmm10" : : "m" (rsa[40])); - asm volatile("movdqa %0,%%xmm11" : : "m" (rsa[44])); - asm volatile("movdqa %0,%%xmm12" : : "m" (rsa[48])); - asm volatile("movdqa %0,%%xmm13" : : "m" (rsa[52])); - asm volatile("movdqa %0,%%xmm14" : : "m" (rsa[56])); - asm volatile("movdqa %0,%%xmm15" : : "m" (rsa[60])); + asm volatile("cpuid" + : "+a" (eax), "=d" (edx) + : : "ecx", "ebx"); - raid6_put_fpu(s->cr0); + return (edx >> (flag & 31)) & 1; } -#endif /* __x86_64__ */ - -/* User space test hack */ -#ifndef __KERNEL__ -static inline int cpuid_features(void) -{ - u32 eax = 1; - u32 ebx, ecx, edx; - - asm volatile("cpuid" : - "+a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)); - - return edx; -} #endif /* ndef __KERNEL__ */ #endif diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 15d12fce34d..127a94b9a1b 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -469,9 +469,9 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, fw->data[BLUEBIRD_01_ID_OFFSET + 1] == USB_VID_DVICO >> 8) { fw->data[BLUEBIRD_01_ID_OFFSET + 2] = - udev->descriptor.idProduct + 1; + le16_to_cpu(udev->descriptor.idProduct) + 1; fw->data[BLUEBIRD_01_ID_OFFSET + 3] = - udev->descriptor.idProduct >> 8; + le16_to_cpu(udev->descriptor.idProduct) >> 8; return usb_cypress_load_firmware(udev, fw, CYPRESS_FX2); } diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 4a198d4755b..b5acb11c0bc 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -119,6 +119,8 @@ static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_f struct dvb_usb_adapter *adap = fe->dvb->priv; u8 b[5]; dvb_usb_tuner_calc_regs(fe,fep,b, 5); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0); } diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c index 682dc7ce48d..710c11a6829 100644 --- a/drivers/media/video/cafe_ccic.c +++ b/drivers/media/video/cafe_ccic.c @@ -1022,7 +1022,7 @@ static ssize_t cafe_v4l_read(struct file *filp, char __user *buffer, size_t len, loff_t *pos) { struct cafe_camera *cam = filp->private_data; - int ret; + int ret = 0; /* * Perhaps we're in speculative read mode and already @@ -1251,8 +1251,6 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv, if (cam->n_sbufs == 0) /* no luck at all - ret already set */ kfree(cam->sb_bufs); - else - ret = 0; req->count = cam->n_sbufs; /* In case of partial success */ out: diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index cc535ca713d..774d2536555 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -633,7 +633,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, { struct v4l2_register *reg = arg; - if (reg->i2c_id != I2C_DRIVERID_CX25840) + if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -903,13 +903,13 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->vbi_line_offset = 8; state->id = id; + i2c_attach_client(client); + if (state->is_cx25836) cx25836_initialize(client); else cx25840_initialize(client, 1); - i2c_attach_client(client); - return 0; } diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c index 1958d4016ea..0e86b9d033a 100644 --- a/drivers/media/video/cx25840/cx25840-firmware.c +++ b/drivers/media/video/cx25840/cx25840-firmware.c @@ -37,7 +37,7 @@ */ #define FWSEND 48 -#define FWDEV(x) &((x)->adapter->dev) +#define FWDEV(x) &((x)->dev) static char *firmware = FWFILE; diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index a1be1e279df..b0466b88f52 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -56,7 +56,8 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); /* ------------------------------------------------------------------ */ -#define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024 +#define OLD_BLACKBIRD_FIRM_IMAGE_SIZE 262144 +#define BLACKBIRD_FIRM_IMAGE_SIZE 376836 /* defines below are from ivtv-driver.h */ @@ -404,7 +405,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev) u32 value; int i; - for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) { + for (i = 0; i < dev->fw_size; i++) { memory_read(dev->core, i, &value); if (value == signature[signaturecnt]) signaturecnt++; @@ -452,12 +453,15 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) return -1; } - if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) { - dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n", - firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE); + if ((firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) && + (firmware->size != OLD_BLACKBIRD_FIRM_IMAGE_SIZE)) { + dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d or %d)\n", + firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE, + OLD_BLACKBIRD_FIRM_IMAGE_SIZE); release_firmware(firmware); return -1; } + dev->fw_size = firmware->size; if (0 != memcmp(firmware->data, magic, 8)) { dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n"); diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index a97be1bdc31..bdfe2af7012 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -1389,7 +1389,7 @@ static int vidioc_g_register (struct file *file, void *fh, { struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; - if (reg->i2c_id != 0) + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) return -EINVAL; /* cx2388x has a 24-bit register space */ reg->val = cx_read(reg->reg&0xffffff); @@ -1401,7 +1401,7 @@ static int vidioc_s_register (struct file *file, void *fh, { struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; - if (reg->i2c_id != 0) + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) return -EINVAL; cx_write(reg->reg&0xffffff, reg->val); return 0; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index d2ecfba9bb4..a4f7befda5b 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -463,6 +463,7 @@ struct cx8802_dev { u32 mailbox; int width; int height; + int fw_size; #if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE) /* for dvb only */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index a1ca0f5007e..1ff5138e4bb 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -1268,7 +1268,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) if (fw_len % sizeof(u32)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "size of %s firmware" - " must be a multiple of %u bytes", + " must be a multiple of %zu bytes", fw_files[fwidx],sizeof(u32)); release_firmware(fw_entry); return -1; @@ -3256,8 +3256,8 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) int pvr2_hdw_register_access(struct pvr2_hdw *hdw, - u32 chip_id, u64 reg_id, - int setFl,u32 *val_ptr) + u32 match_type, u32 match_chip, u64 reg_id, + int setFl,u64 *val_ptr) { #ifdef CONFIG_VIDEO_ADV_DEBUG struct list_head *item; @@ -3268,13 +3268,16 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw, if (!capable(CAP_SYS_ADMIN)) return -EPERM; - req.i2c_id = chip_id; + req.match_type = match_type; + req.match_chip = match_chip; req.reg = reg_id; if (setFl) req.val = *val_ptr; mutex_lock(&hdw->i2c_list_lock); do { list_for_each(item,&hdw->i2c_clients) { cp = list_entry(item,struct pvr2_i2c_client,list); - if (cp->client->driver->id != chip_id) continue; + if (!v4l2_chip_match_i2c_client(cp->client, req.match_type, req.match_chip)) { + continue; + } stat = pvr2_i2c_client_cmd( cp,(setFl ? VIDIOC_DBG_S_REGISTER : VIDIOC_DBG_G_REGISTER),&req); diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 566a8ef7e12..0c9cca43ff8 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -217,13 +217,14 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *, enum pvr2_v4l_type index,int); /* Direct read/write access to chip's registers: - chip_id - unique id of chip (e.g. I2C_DRIVERD_xxxx) + match_type - how to interpret match_chip (e.g. driver ID, i2c address) + match_chip - chip match value (e.g. I2C_DRIVERD_xxxx) reg_id - register number to access setFl - true to set the register, false to read it val_ptr - storage location for source / result. */ int pvr2_hdw_register_access(struct pvr2_hdw *, - u32 chip_id,u64 reg_id, - int setFl,u32 *val_ptr); + u32 match_type, u32 match_chip,u64 reg_id, + int setFl,u64 *val_ptr); /* The following entry points are all lower level things you normally don't want to worry about. */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 4fe4136204c..5313d342666 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -740,11 +740,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_DBG_S_REGISTER: case VIDIOC_DBG_G_REGISTER: { - u32 val; + u64 val; struct v4l2_register *req = (struct v4l2_register *)arg; if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val; ret = pvr2_hdw_register_access( - hdw,req->i2c_id,req->reg, + hdw,req->match_type,req->match_chip,req->reg, cmd == VIDIOC_DBG_S_REGISTER,&val); if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val; break; diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index c4f066d6668..7735b675892 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1425,7 +1425,7 @@ static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *ar { struct v4l2_register *reg = arg; - if (reg->i2c_id != I2C_DRIVERID_SAA711X) + if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index bd9c4f3ad02..654863db159 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -619,7 +619,7 @@ static int saa7127_command(struct i2c_client *client, { struct v4l2_register *reg = arg; - if (reg->i2c_id != I2C_DRIVERID_SAA7127) + if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 886b5df7c9d..d5ec05f56ad 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -955,7 +955,7 @@ static int tvp5150_command(struct i2c_client *c, { struct v4l2_register *reg = arg; - if (reg->i2c_id != I2C_DRIVERID_TVP5150) + if (!v4l2_chip_match_i2c_client(c, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index b3b5fd536dc..28d1133a3b7 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -167,7 +167,7 @@ static int upd64031a_command(struct i2c_client *client, unsigned int cmd, void * { struct v4l2_register *reg = arg; - if (reg->i2c_id != I2C_DRIVERID_UPD64031A) + if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 8852903e7a9..fe38224150d 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -144,7 +144,7 @@ static int upd64083_command(struct i2c_client *client, unsigned int cmd, void *a { struct v4l2_register *reg = arg; - if (reg->i2c_id != I2C_DRIVERID_UPD64083) + if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c index ae5f42562c0..6fc14557d62 100644 --- a/drivers/media/video/usbvision/usbvision-video.c +++ b/drivers/media/video/usbvision/usbvision-video.c @@ -521,7 +521,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, struct v4l2_register *reg = arg; int errCode; - if (reg->i2c_id != 0) + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) return -EINVAL; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -540,7 +540,7 @@ static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file, PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X", cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', - (unsigned int)reg->reg, reg->val); + (unsigned int)reg->reg, (unsigned int)reg->val); return 0; } #endif diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index ddfd80c5618..54747606eae 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -51,6 +51,7 @@ #include <linux/mm.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/i2c.h> #include <asm/uaccess.h> #include <asm/system.h> #include <asm/pgtable.h> @@ -365,13 +366,21 @@ static const char *v4l2_ioctls[] = { [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", -#if 1 [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", -#endif [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS", [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", - [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS" + [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", +#if 1 + [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", + [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", + [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX", + [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", + [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", + + [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", + [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", +#endif }; #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) @@ -395,9 +404,6 @@ static const char *v4l2_int_ioctls[] = { [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", [_IOC_NR(TDA9887_SET_CONFIG)] = "TDA9887_SET_CONFIG", - [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", - [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", - [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", @@ -947,6 +953,28 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id) return **ctrl_classes; } +int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_chip) +{ + switch (match_type) { + case V4L2_CHIP_MATCH_I2C_DRIVER: + return (c != NULL && c->driver != NULL && c->driver->id == match_chip); + case V4L2_CHIP_MATCH_I2C_ADDR: + return (c != NULL && c->addr == match_chip); + default: + return 0; + } +} + +int v4l2_chip_match_host(u32 match_type, u32 match_chip) +{ + switch (match_type) { + case V4L2_CHIP_MATCH_HOST: + return match_chip == 0; + default: + return 0; + } +} + /* ----------------------------------------------------------------- */ EXPORT_SYMBOL(v4l2_norm_to_name); @@ -970,6 +998,9 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu); EXPORT_SYMBOL(v4l2_ctrl_query_fill); EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); +EXPORT_SYMBOL(v4l2_chip_match_i2c_client); +EXPORT_SYMBOL(v4l2_chip_match_host); + /* * Local variables: * c-basic-offset: 8 diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index dc9b1ef678a..011938fb7e0 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -1342,6 +1342,42 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_s_jpegcomp(file, fh, p); break; } + case VIDIOC_G_ENC_INDEX: + { + struct v4l2_enc_idx *p=arg; + + if (!vfd->vidioc_g_enc_index) + break; + ret=vfd->vidioc_g_enc_index(file, fh, p); + if (!ret) + dbgarg (cmd, "entries=%d, entries_cap=%d\n", + p->entries,p->entries_cap); + break; + } + case VIDIOC_ENCODER_CMD: + { + struct v4l2_encoder_cmd *p=arg; + + if (!vfd->vidioc_encoder_cmd) + break; + ret=vfd->vidioc_encoder_cmd(file, fh, p); + if (!ret) + dbgarg (cmd, "cmd=%d, flags=%d\n", + p->cmd,p->flags); + break; + } + case VIDIOC_TRY_ENCODER_CMD: + { + struct v4l2_encoder_cmd *p=arg; + + if (!vfd->vidioc_try_encoder_cmd) + break; + ret=vfd->vidioc_try_encoder_cmd(file, fh, p); + if (!ret) + dbgarg (cmd, "cmd=%d, flags=%d\n", + p->cmd,p->flags); + break; + } case VIDIOC_G_PARM: { struct v4l2_streamparm *p=arg; diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 5c5a1e2dda8..c707c8ebc1a 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1131,7 +1131,7 @@ static struct platform_driver sm501_plat_drv = { static int __init sm501_base_init(void) { platform_driver_register(&sm501_plat_drv); - return pci_module_init(&sm501_pci_drv); + return pci_register_driver(&sm501_pci_drv); } static void __exit sm501_base_exit(void) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 5046a166134..4a73e8b2428 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -376,10 +376,11 @@ static inline void mmc_set_ios(struct mmc_host *host) { struct mmc_ios *ios = &host->ios; - pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u width %u\n", + pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u " + "width %u timing %u\n", mmc_hostname(host), ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, ios->vdd, - ios->bus_width); + ios->bus_width, ios->timing); host->ops->set_ios(host, ios); } @@ -809,6 +810,7 @@ static void mmc_power_up(struct mmc_host *host) host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); mmc_delay(1); @@ -828,6 +830,7 @@ static void mmc_power_off(struct mmc_host *host) host->ios.chip_select = MMC_CS_DONTCARE; host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; + host->ios.timing = MMC_TIMING_LEGACY; mmc_set_ios(host); } @@ -1112,46 +1115,50 @@ static void mmc_process_ext_csds(struct mmc_host *host) continue; } - /* Activate highspeed support. */ - cmd.opcode = MMC_SWITCH; - cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | - (EXT_CSD_HS_TIMING << 16) | - (1 << 8) | - EXT_CSD_CMD_SET_NORMAL; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + if (host->caps & MMC_CAP_MMC_HIGHSPEED) { + /* Activate highspeed support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_HS_TIMING << 16) | + (1 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); - if (err != MMC_ERR_NONE) { - printk("%s: failed to switch card to mmc v4 " - "high-speed mode.\n", - mmc_hostname(card->host)); - continue; - } + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to mmc v4 " + "high-speed mode.\n", + mmc_hostname(card->host)); + continue; + } - mmc_card_set_highspeed(card); + mmc_card_set_highspeed(card); - /* Check for host support for wide-bus modes. */ - if (!(host->caps & MMC_CAP_4_BIT_DATA)) { - continue; + host->ios.timing = MMC_TIMING_SD_HS; + mmc_set_ios(host); } - /* Activate 4-bit support. */ - cmd.opcode = MMC_SWITCH; - cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | - (EXT_CSD_BUS_WIDTH << 16) | - (EXT_CSD_BUS_WIDTH_4 << 8) | - EXT_CSD_CMD_SET_NORMAL; - cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + /* Check for host support for wide-bus modes. */ + if (host->caps & MMC_CAP_4_BIT_DATA) { + /* Activate 4-bit support. */ + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BUS_WIDTH << 16) | + (EXT_CSD_BUS_WIDTH_4 << 8) | + EXT_CSD_CMD_SET_NORMAL; + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); - if (err != MMC_ERR_NONE) { - printk("%s: failed to switch card to " - "mmc v4 4-bit bus mode.\n", - mmc_hostname(card->host)); - continue; - } + err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); + if (err != MMC_ERR_NONE) { + printk("%s: failed to switch card to " + "mmc v4 4-bit bus mode.\n", + mmc_hostname(card->host)); + continue; + } - host->ios.bus_width = MMC_BUS_WIDTH_4; + host->ios.bus_width = MMC_BUS_WIDTH_4; + mmc_set_ios(host); + } } kfree(ext_csd); @@ -1241,6 +1248,9 @@ static void mmc_read_switch_caps(struct mmc_host *host) unsigned char *status; struct scatterlist sg; + if (!(host->caps & MMC_CAP_SD_HIGHSPEED)) + return; + status = kmalloc(64, GFP_KERNEL); if (!status) { printk(KERN_WARNING "%s: Unable to allocate buffer for " @@ -1332,6 +1342,9 @@ static void mmc_read_switch_caps(struct mmc_host *host) } mmc_card_set_highspeed(card); + + host->ios.timing = MMC_TIMING_SD_HS; + mmc_set_ios(host); } kfree(status); diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 7522f76b15e..d749f08601b 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -606,7 +606,6 @@ static void sdhci_finish_command(struct sdhci_host *host) static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { int div; - u8 ctrl; u16 clk; unsigned long timeout; @@ -615,13 +614,6 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); - ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); - if (clock > 25000000) - ctrl |= SDHCI_CTRL_HISPD; - else - ctrl &= ~SDHCI_CTRL_HISPD; - writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); - if (clock == 0) goto out; @@ -761,10 +753,17 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_set_power(host, ios->vdd); ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); + if (ios->bus_width == MMC_BUS_WIDTH_4) ctrl |= SDHCI_CTRL_4BITBUS; else ctrl &= ~SDHCI_CTRL_4BITBUS; + + if (ios->timing == MMC_TIMING_SD_HS) + ctrl |= SDHCI_CTRL_HISPD; + else + ctrl &= ~SDHCI_CTRL_HISPD; + writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); mmiowb(); @@ -994,7 +993,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask = readl(host->ioaddr + SDHCI_INT_STATUS); - if (!intmask) { + if (!intmask || intmask == 0xffffffff) { result = IRQ_NONE; goto out; } @@ -1080,6 +1079,13 @@ static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + + for (i = 0;i < chip->num_slots;i++) { + if (!chip->hosts[i]) + continue; + free_irq(chip->hosts[i]->irq, chip->hosts[i]); + } + pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); @@ -1108,6 +1114,11 @@ static int sdhci_resume (struct pci_dev *pdev) continue; if (chip->hosts[i]->flags & SDHCI_USE_DMA) pci_set_master(pdev); + ret = request_irq(chip->hosts[i]->irq, sdhci_irq, + IRQF_SHARED, chip->hosts[i]->slot_descr, + chip->hosts[i]); + if (ret) + return ret; sdhci_init(chip->hosts[i]); mmiowb(); ret = mmc_resume_host(chip->hosts[i]->mmc); @@ -1274,6 +1285,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->f_max = host->max_clk; mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK; + if (caps & SDHCI_CAN_DO_HISPD) + mmc->caps |= MMC_CAP_SD_HIGHSPEED; + mmc->ocr_avail = 0; if (caps & SDHCI_CAN_VDD_330) mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; @@ -1282,13 +1296,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) if (caps & SDHCI_CAN_VDD_180) mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; - if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) { - printk(KERN_ERR "%s: Controller reports > 25 MHz base clock," - " but no high speed support.\n", - host->slot_descr); - mmc->f_max = 25000000; - } - if (mmc->ocr_avail == 0) { printk(KERN_ERR "%s: Hardware doesn't report any " "support voltages.\n", host->slot_descr); diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index e3acd398fb3..1f644584046 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -359,6 +359,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp; cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp; cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp; + cfi->chips[i].ref_point_counter = 0; + init_waitqueue_head(&(cfi->chips[i].wq)); } map->fldrv = &cfi_amdstd_chipdrv; diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 69d49e0250a..b344ff858b2 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -158,6 +158,8 @@ struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary) cfi->chips[i].word_write_time = 128; cfi->chips[i].buffer_write_time = 128; cfi->chips[i].erase_time = 1024; + cfi->chips[i].ref_point_counter = 0; + init_waitqueue_head(&(cfi->chips[i].wq)); } return cfi_staa_setup(map); diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c index b1104fe1f20..1c3b34ad732 100644 --- a/drivers/mtd/maps/dilnetpc.c +++ b/drivers/mtd/maps/dilnetpc.c @@ -402,8 +402,8 @@ static int __init init_dnpc(void) ++higlvl_partition_info[i].name; } - printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", - is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); + printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%llx\n", + is_dnp ? "DNPC" : "ADNP", dnpc_map.size, (unsigned long long)dnpc_map.phys); dnpc_map.virt = ioremap_nocache(dnpc_map.phys, dnpc_map.size); diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index 0bc013fd66a..aa64a475278 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -30,7 +30,7 @@ #define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */ -#define BIOS_CNTL 0xDC +#define BIOS_CNTL 0xDC #define BIOS_LOCK_ENABLE 0x02 #define BIOS_WRITE_ENABLE 0x01 @@ -145,7 +145,7 @@ static void esb2rom_cleanup(struct esb2rom_window *window) } static int __devinit esb2rom_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) + const struct pci_device_id *ent) { static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; struct esb2rom_window *window = &esb2rom_window; @@ -185,7 +185,7 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, /* Find a region continuous to the end of the ROM window */ window->phys = 0; pci_read_config_word(pdev, FWH_DEC_EN1, &word); - printk(KERN_DEBUG "pci_read_config_byte : %x\n", word); + printk(KERN_DEBUG "pci_read_config_word : %x\n", word); if ((word & FWH_8MiB) == FWH_8MiB) window->phys = 0xff400000; @@ -212,6 +212,11 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, else if ((word & FWH_0_5MiB) == FWH_0_5MiB) window->phys = 0xfff80000; + if (window->phys == 0) { + printk(KERN_ERR MOD_NAME ": Rom window is closed\n"); + goto out; + } + /* reserved 0x0020 and 0x0010 */ window->phys -= 0x400000UL; window->size = (0xffffffffUL - window->phys) + 1UL; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 880580c44e0..41844ea0246 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -727,6 +727,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.erasesize = subdev[0]->erasesize; concat->mtd.writesize = subdev[0]->writesize; concat->mtd.oobsize = subdev[0]->oobsize; + concat->mtd.oobavail = subdev[0]->oobavail; if (subdev[0]->writev) concat->mtd.writev = concat_writev; if (subdev[0]->read_oob) diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 633def3fb08..1af989023c6 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -200,6 +200,11 @@ static int part_erase (struct mtd_info *mtd, struct erase_info *instr) return -EINVAL; instr->addr += part->offset; ret = part->master->erase(part->master, instr); + if (ret) { + if (instr->fail_addr != 0xffffffff) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; + } return ret; } @@ -338,6 +343,7 @@ int add_mtd_partitions(struct mtd_info *master, slave->mtd.size = parts[i].size; slave->mtd.writesize = master->writesize; slave->mtd.oobsize = master->oobsize; + slave->mtd.oobavail = master->oobavail; slave->mtd.subpage_sft = master->subpage_sft; slave->mtd.name = parts[i].name; @@ -559,4 +565,3 @@ EXPORT_SYMBOL_GPL(deregister_mtd_parser); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); MODULE_DESCRIPTION("Generic support for partitioning of MTD devices"); - diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 12608c13cce..595208f965a 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -114,7 +114,7 @@ module_param(no_autopart, int, 0); static int show_firmware_partition = 0; module_param(show_firmware_partition, int, 0); -#ifdef MTD_NAND_DISKONCHIP_BBTWRITE +#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE static int inftl_bbt_write = 1; #else static int inftl_bbt_write = 0; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index acaf97bc80d..6af37b8cff6 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2524,6 +2524,7 @@ int nand_scan_tail(struct mtd_info *mtd) for (i = 0; chip->ecc.layout->oobfree[i].length; i++) chip->ecc.layout->oobavail += chip->ecc.layout->oobfree[i].length; + mtd->oobavail = chip->ecc.layout->oobavail; /* * Set the number of read / write steps for one page depending on ECC diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 0ddfd6de75c..5fac4c421a2 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -473,7 +473,7 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u ecc_code[1] = ecc >> 8; ecc_code[2] = ecc >> 16; - pr_debug("%s: returning ecc %06x\n", __func__, ecc); + pr_debug("%s: returning ecc %06lx\n", __func__, ecc); return 0; } diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7f1cb6e5dcc..9e14a26ca4e 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -4,6 +4,11 @@ * Copyright (C) 2005-2007 Samsung Electronics * Kyungmin Park <kyungmin.park@samsung.com> * + * Credits: + * Adrian Hunter <ext-adrian.hunter@nokia.com>: + * auto-placement support, read-while load support, various fixes + * Copyright (C) Nokia Corporation, 2007 + * * 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. @@ -831,7 +836,7 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col int readcol = column; int readend = column + thislen; int lastgap = 0; - uint8_t *oob_buf = this->page_buf + mtd->writesize; + uint8_t *oob_buf = this->oob_buf; for (free = this->ecclayout->oobfree; free->length; ++free) { if (readcol >= lastgap) @@ -849,7 +854,8 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf, int col int n = ed - st; memcpy(buf, oob_buf + st, n); buf += n; - } + } else + break; } return 0; } @@ -947,9 +953,9 @@ static int onenand_do_read_oob(struct mtd_info *mtd, loff_t from, size_t len, /** * onenand_read_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operation description structure + * @param mtd: MTD device structure + * @param from: offset to read from + * @param ops: oob operation description structure */ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) @@ -1017,7 +1023,7 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state) * onenand_bbt_read_oob - [MTD Interface] OneNAND read out-of-band for bbt scan * @param mtd MTD device structure * @param from offset to read from - * @param @ops oob operation description structure + * @param ops oob operation description structure * * OneNAND read out-of-band data from the spare area for bbt scan */ @@ -1093,7 +1099,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to) { struct onenand_chip *this = mtd->priv; - char *readp = this->page_buf + mtd->writesize; + char oobbuf[64]; int status, i; this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize); @@ -1102,9 +1108,9 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to if (status) return status; - this->read_bufferram(mtd, ONENAND_SPARERAM, readp, 0, mtd->oobsize); - for(i = 0; i < mtd->oobsize; i++) - if (buf[i] != 0xFF && buf[i] != readp[i]) + this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); + for (i = 0; i < mtd->oobsize; i++) + if (buf[i] != 0xFF && buf[i] != oobbuf[i]) return -EBADMSG; return 0; @@ -1290,7 +1296,8 @@ static int onenand_fill_auto_oob(struct mtd_info *mtd, u_char *oob_buf, int n = ed - st; memcpy(oob_buf + st, buf, n); buf += n; - } + } else + break; } return 0; } @@ -1312,6 +1319,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, struct onenand_chip *this = mtd->priv; int column, ret = 0, oobsize; int written = 0; + u_char *oobbuf; DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); @@ -1331,7 +1339,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, } /* For compatibility with NAND: Do not allow write past end of page */ - if (column + len > oobsize) { + if (unlikely(column + len > oobsize)) { printk(KERN_ERR "onenand_write_oob: " "Attempt to write past end of page\n"); return -EINVAL; @@ -1348,6 +1356,8 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_WRITING); + oobbuf = this->oob_buf; + /* Loop until all data write */ while (written < len) { int thislen = min_t(int, oobsize, len - written); @@ -1358,12 +1368,12 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, /* We send data to spare ram with oobsize * to prevent byte access */ - memset(this->page_buf, 0xff, mtd->oobsize); + memset(oobbuf, 0xff, mtd->oobsize); if (mode == MTD_OOB_AUTO) - onenand_fill_auto_oob(mtd, this->page_buf, buf, column, thislen); + onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen); else - memcpy(this->page_buf + column, buf, thislen); - this->write_bufferram(mtd, ONENAND_SPARERAM, this->page_buf, 0, mtd->oobsize); + memcpy(oobbuf + column, buf, thislen); + this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize); this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize); @@ -1375,7 +1385,7 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, break; } - ret = onenand_verify_oob(mtd, this->page_buf, to); + ret = onenand_verify_oob(mtd, oobbuf, to); if (ret) { printk(KERN_ERR "onenand_write_oob: verify failed %d\n", ret); break; @@ -1400,9 +1410,9 @@ static int onenand_do_write_oob(struct mtd_info *mtd, loff_t to, size_t len, /** * onenand_write_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operation description structure + * @param mtd: MTD device structure + * @param to: offset to write + * @param ops: oob operation description structure */ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -1616,6 +1626,7 @@ static int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) * @param mtd MTD device structure * @param ofs offset relative to mtd start * @param len number of bytes to lock or unlock + * @param cmd lock or unlock command * * Lock or unlock one or more blocks */ @@ -2117,10 +2128,11 @@ static void onenand_check_features(struct mtd_info *mtd) } /** - * onenand_print_device_info - Print device ID + * onenand_print_device_info - Print device & version ID * @param device device ID + * @param version version ID * - * Print device ID + * Print device & version ID */ static void onenand_print_device_info(int device, int version) { @@ -2320,15 +2332,25 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) /* Allocate buffers, if necessary */ if (!this->page_buf) { - size_t len; - len = mtd->writesize + mtd->oobsize; - this->page_buf = kmalloc(len, GFP_KERNEL); + this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL); if (!this->page_buf) { printk(KERN_ERR "onenand_scan(): Can't allocate page_buf\n"); return -ENOMEM; } this->options |= ONENAND_PAGEBUF_ALLOC; } + if (!this->oob_buf) { + this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL); + if (!this->oob_buf) { + printk(KERN_ERR "onenand_scan(): Can't allocate oob_buf\n"); + if (this->options & ONENAND_PAGEBUF_ALLOC) { + this->options &= ~ONENAND_PAGEBUF_ALLOC; + kfree(this->page_buf); + } + return -ENOMEM; + } + this->options |= ONENAND_OOBBUF_ALLOC; + } this->state = FL_READY; init_waitqueue_head(&this->wq); @@ -2367,6 +2389,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) for (i = 0; this->ecclayout->oobfree[i].length; i++) this->ecclayout->oobavail += this->ecclayout->oobfree[i].length; + mtd->oobavail = this->ecclayout->oobavail; mtd->ecclayout = this->ecclayout; @@ -2424,9 +2447,11 @@ void onenand_release(struct mtd_info *mtd) kfree(bbm->bbt); kfree(this->bbm); } - /* Buffer allocated by onenand_scan */ + /* Buffers allocated by onenand_scan */ if (this->options & ONENAND_PAGEBUF_ALLOC) kfree(this->page_buf); + if (this->options & ONENAND_OOBBUF_ALLOC) + kfree(this->oob_buf); } EXPORT_SYMBOL_GPL(onenand_scan); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 716a47210aa..b406ecfa726 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -822,11 +822,17 @@ static int vortex_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct vortex_private *vp = netdev_priv(dev); + int err; if (dev && vp) { pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); - pci_enable_device(pdev); + err = pci_enable_device(pdev); + if (err) { + printk(KERN_WARNING "%s: Could not enable device \n", + dev->name); + return err; + } pci_set_master(pdev); if (request_irq(dev->irq, vp->full_bus_master_rx ? &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev)) { @@ -852,19 +858,7 @@ static struct eisa_device_id vortex_eisa_ids[] = { }; MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids); -static int vortex_eisa_probe(struct device *device); -static int vortex_eisa_remove(struct device *device); - -static struct eisa_driver vortex_eisa_driver = { - .id_table = vortex_eisa_ids, - .driver = { - .name = "3c59x", - .probe = vortex_eisa_probe, - .remove = vortex_eisa_remove - } -}; - -static int vortex_eisa_probe(struct device *device) +static int __init vortex_eisa_probe(struct device *device) { void __iomem *ioaddr; struct eisa_device *edev; @@ -887,7 +881,7 @@ static int vortex_eisa_probe(struct device *device) return 0; } -static int vortex_eisa_remove(struct device *device) +static int __devexit vortex_eisa_remove(struct device *device) { struct eisa_device *edev; struct net_device *dev; @@ -912,7 +906,17 @@ static int vortex_eisa_remove(struct device *device) free_netdev(dev); return 0; } -#endif + +static struct eisa_driver vortex_eisa_driver = { + .id_table = vortex_eisa_ids, + .driver = { + .name = "3c59x", + .probe = vortex_eisa_probe, + .remove = __devexit_p(vortex_eisa_remove) + } +}; + +#endif /* CONFIG_EISA */ /* returns count found (>= 0), or negative on error */ static int __init vortex_eisa_init(void) diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 6f93a765e56..12c8453f44b 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -448,8 +448,7 @@ static void cp_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) spin_lock_irqsave(&cp->lock, flags); cp->cpcmd &= ~RxVlanOn; cpw16(CpCmd, cp->cpcmd); - if (cp->vlgrp) - cp->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(cp->vlgrp, vid, NULL); spin_unlock_irqrestore(&cp->lock, flags); } #endif /* CP_VLAN_TAG_USED */ diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9d5c083f333..5ff0922e628 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -430,10 +430,10 @@ config HPLANCE config LASI_82596 tristate "Lasi ethernet" - depends on NET_ETHERNET && PARISC && GSC_LASI + depends on NET_ETHERNET && GSC help - Say Y here to support the on-board Intel 82596 ethernet controller - built into Hewlett-Packard PA-RISC machines. + Say Y here to support the builtin Intel 82596 ethernet controller + found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet. config MIPS_JAZZ_SONIC tristate "MIPS JAZZ onboard SONIC Ethernet support" @@ -2245,7 +2245,7 @@ config BNX2 config SPIDER_NET tristate "Spider Gigabit Ethernet driver" - depends on PCI && PPC_IBM_CELL_BLADE + depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB) select FW_LOADER help This driver supports the Gigabit Ethernet chips present on the diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 33c6645455a..7138e0e025b 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -2293,10 +2293,7 @@ static void ace_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) local_irq_save(flags); ace_mask_irq(dev); - - if (ap->vlgrp) - ap->vlgrp->vlan_devices[vid] = NULL; - + vlan_group_set_device(ap->vlgrp, vid, NULL); ace_unmask_irq(dev); local_irq_restore(flags); } diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 9c399aaefbd..962c954c2d5 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1737,8 +1737,7 @@ static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid { struct amd8111e_priv *lp = netdev_priv(dev); spin_lock_irq(&lp->lock); - if (lp->vlgrp) - lp->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(lp->vlgrp, vid, NULL); spin_unlock_irq(&lp->lock); } #endif diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 65673485bb6..88d4f70035b 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -1252,8 +1252,7 @@ static void atl1_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) spin_lock_irqsave(&adapter->lock, flags); /* atl1_irq_disable(adapter); */ - if (adapter->vlgrp) - adapter->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(adapter->vlgrp, vid, NULL); /* atl1_irq_enable(adapter); */ spin_unlock_irqrestore(&adapter->lock, flags); /* We don't do Vlan filtering */ @@ -1266,7 +1265,7 @@ static void atl1_restore_vlan(struct atl1_adapter *adapter) if (adapter->vlgrp) { u16 vid; for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { - if (!adapter->vlgrp->vlan_devices[vid]) + if (!vlan_group_get_device(adapter->vlgrp, vid)) continue; atl1_vlan_rx_add_vid(adapter->netdev, vid); } diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 5a96d7611af..c12e5ea6181 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4467,9 +4467,7 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) struct bnx2 *bp = netdev_priv(dev); bnx2_netif_stop(bp); - - if (bp->vlgrp) - bp->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(bp->vlgrp, vid, NULL); bnx2_set_rx_mode(dev); bnx2_netif_start(bp); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a7c8f98a890..e4724d874e7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -60,6 +60,7 @@ #include <linux/errno.h> #include <linux/netdevice.h> #include <linux/inetdevice.h> +#include <linux/igmp.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <net/sock.h> @@ -488,9 +489,9 @@ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) /* Save and then restore vlan_dev in the grp array, * since the slave's driver might clear it. */ - vlan_dev = bond->vlgrp->vlan_devices[vid]; + vlan_dev = vlan_group_get_device(bond->vlgrp, vid); slave_dev->vlan_rx_kill_vid(slave_dev, vid); - bond->vlgrp->vlan_devices[vid] = vlan_dev; + vlan_group_set_device(bond->vlgrp, vid, vlan_dev); } } @@ -550,9 +551,9 @@ static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *s /* Save and then restore vlan_dev in the grp array, * since the slave's driver might clear it. */ - vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; + vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id); - bond->vlgrp->vlan_devices[vlan->vlan_id] = vlan_dev; + vlan_group_set_device(bond->vlgrp, vlan->vlan_id, vlan_dev); } unreg: @@ -861,6 +862,28 @@ static void bond_mc_delete(struct bonding *bond, void *addr, int alen) } } + +/* + * Retrieve the list of registered multicast addresses for the bonding + * device and retransmit an IGMP JOIN request to the current active + * slave. + */ +static void bond_resend_igmp_join_requests(struct bonding *bond) +{ + struct in_device *in_dev; + struct ip_mc_list *im; + + rcu_read_lock(); + in_dev = __in_dev_get_rcu(bond->dev); + if (in_dev) { + for (im = in_dev->mc_list; im; im = im->next) { + ip_mc_rejoin_group(im); + } + } + + rcu_read_unlock(); +} + /* * Totally destroys the mc_list in bond */ @@ -874,6 +897,7 @@ static void bond_mc_list_destroy(struct bonding *bond) kfree(dmi); dmi = bond->mc_list; } + bond->mc_list = NULL; } /* @@ -967,6 +991,7 @@ static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) { dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); } + bond_resend_igmp_join_requests(bond); } } @@ -2397,7 +2422,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) vlan_id = 0; list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, vlan_list) { - vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; + vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan_dev == rt->u.dst.dev) { vlan_id = vlan->vlan_id; dprintk("basa: vlan match on %s %d\n", @@ -2444,7 +2469,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond) } list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; + vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan->vlan_ip) { bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip, vlan->vlan_ip, vlan->vlan_id); @@ -3371,7 +3396,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list, vlan_list) { - vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id]; + vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan_dev == event_dev) { switch (event) { case NETDEV_UP: @@ -3423,15 +3448,21 @@ void bond_register_arp(struct bonding *bond) { struct packet_type *pt = &bond->arp_mon_pt; + if (pt->type) + return; + pt->type = htons(ETH_P_ARP); - pt->dev = NULL; /*bond->dev;XXX*/ + pt->dev = bond->dev; pt->func = bond_arp_rcv; dev_add_pack(pt); } void bond_unregister_arp(struct bonding *bond) { - dev_remove_pack(&bond->arp_mon_pt); + struct packet_type *pt = &bond->arp_mon_pt; + + dev_remove_pack(pt); + pt->type = 0; } /*---------------------------- Hashing Policies -----------------------------*/ @@ -4011,42 +4042,6 @@ out: return 0; } -static void bond_activebackup_xmit_copy(struct sk_buff *skb, - struct bonding *bond, - struct slave *slave) -{ - struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); - struct ethhdr *eth_data; - u8 *hwaddr; - int res; - - if (!skb2) { - printk(KERN_ERR DRV_NAME ": Error: " - "bond_activebackup_xmit_copy(): skb_copy() failed\n"); - return; - } - - skb2->mac.raw = (unsigned char *)skb2->data; - eth_data = eth_hdr(skb2); - - /* Pick an appropriate source MAC address - * -- use slave's perm MAC addr, unless used by bond - * -- otherwise, borrow active slave's perm MAC addr - * since that will not be used - */ - hwaddr = slave->perm_hwaddr; - if (!memcmp(eth_data->h_source, hwaddr, ETH_ALEN)) - hwaddr = bond->curr_active_slave->perm_hwaddr; - - /* Set source MAC address appropriately */ - memcpy(eth_data->h_source, hwaddr, ETH_ALEN); - - res = bond_dev_queue_xmit(bond, skb2, slave->dev); - if (res) - dev_kfree_skb(skb2); - - return; -} /* * in active-backup mode, we know that bond->curr_active_slave is always valid if @@ -4067,21 +4062,6 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d if (!bond->curr_active_slave) goto out; - /* Xmit IGMP frames on all slaves to ensure rapid fail-over - for multicast traffic on snooping switches */ - if (skb->protocol == __constant_htons(ETH_P_IP) && - skb->nh.iph->protocol == IPPROTO_IGMP) { - struct slave *slave, *active_slave; - int i; - - active_slave = bond->curr_active_slave; - bond_for_each_slave_from_to(bond, slave, i, active_slave->next, - active_slave->prev) - if (IS_UP(slave->dev) && - (slave->link == BOND_LINK_UP)) - bond_activebackup_xmit_copy(skb, bond, slave); - } - res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev); out: diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 7d0f24f6977..125c9b10586 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -889,8 +889,7 @@ static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) struct adapter *adapter = dev->priv; spin_lock_irq(&adapter->async_lock); - if (adapter->vlan_grp) - adapter->vlan_grp->vlan_devices[vid] = NULL; + vlan_group_set_device(adapter->vlan_grp, vid, NULL); spin_unlock_irq(&adapter->async_lock); } #endif diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 89a682702fa..326d4a66512 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1696,6 +1696,7 @@ irqreturn_t t1_interrupt(int irq, void *cookie) { int work_done; struct adapter *adapter = cookie; + struct respQ *Q = &adapter->sge->respQ; spin_lock(&adapter->async_lock); diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 5c97a64451c..80c3d8f268a 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -74,6 +74,11 @@ enum { /* adapter flags */ struct rx_desc; struct rx_sw_desc; +struct sge_fl_page { + struct skb_frag_struct frag; + unsigned char *va; +}; + struct sge_fl { /* SGE per free-buffer list state */ unsigned int buf_size; /* size of each Rx buffer */ unsigned int credits; /* # of available Rx buffers */ @@ -81,11 +86,13 @@ struct sge_fl { /* SGE per free-buffer list state */ unsigned int cidx; /* consumer index */ unsigned int pidx; /* producer index */ unsigned int gen; /* free list generation */ + unsigned int cntxt_id; /* SGE context id for the free list */ + struct sge_fl_page page; struct rx_desc *desc; /* address of HW Rx descriptor ring */ struct rx_sw_desc *sdesc; /* address of SW Rx descriptor ring */ dma_addr_t phys_addr; /* physical address of HW ring start */ - unsigned int cntxt_id; /* SGE context id for the free list */ unsigned long empty; /* # of times queue ran out of buffers */ + unsigned long alloc_failed; /* # of times buffer allocation failed */ }; /* @@ -121,6 +128,8 @@ struct sge_rspq { /* state for an SGE response queue */ unsigned long empty; /* # of times queue ran out of credits */ unsigned long nomem; /* # of responses deferred due to no mem */ unsigned long unhandled_irqs; /* # of spurious intrs */ + unsigned long starved; + unsigned long restarted; }; struct tx_desc; diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h index a94281861a6..0a82fcddf2d 100644 --- a/drivers/net/cxgb3/cxgb3_ioctl.h +++ b/drivers/net/cxgb3/cxgb3_ioctl.h @@ -36,28 +36,17 @@ * Ioctl commands specific to this driver. */ enum { - CHELSIO_SETREG = 1024, - CHELSIO_GETREG, - CHELSIO_SETTPI, - CHELSIO_GETTPI, - CHELSIO_GETMTUTAB, - CHELSIO_SETMTUTAB, - CHELSIO_GETMTU, - CHELSIO_SET_PM, - CHELSIO_GET_PM, - CHELSIO_GET_TCAM, - CHELSIO_SET_TCAM, - CHELSIO_GET_TCB, - CHELSIO_GET_MEM, - CHELSIO_LOAD_FW, - CHELSIO_GET_PROTO, - CHELSIO_SET_PROTO, - CHELSIO_SET_TRACE_FILTER, - CHELSIO_SET_QSET_PARAMS, - CHELSIO_GET_QSET_PARAMS, - CHELSIO_SET_QSET_NUM, - CHELSIO_GET_QSET_NUM, - CHELSIO_SET_PKTSCHED, + CHELSIO_GETMTUTAB = 1029, + CHELSIO_SETMTUTAB = 1030, + CHELSIO_SET_PM = 1032, + CHELSIO_GET_PM = 1033, + CHELSIO_GET_MEM = 1038, + CHELSIO_LOAD_FW = 1041, + CHELSIO_SET_TRACE_FILTER = 1044, + CHELSIO_SET_QSET_PARAMS = 1045, + CHELSIO_GET_QSET_PARAMS = 1046, + CHELSIO_SET_QSET_NUM = 1047, + CHELSIO_GET_QSET_NUM = 1048, }; struct ch_reg { diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 43583ed655a..7ff834e45d6 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -434,27 +434,25 @@ static int setup_sge_qsets(struct adapter *adap) static ssize_t attr_show(struct device *d, struct device_attribute *attr, char *buf, - ssize_t(*format) (struct adapter *, char *)) + ssize_t(*format) (struct net_device *, char *)) { ssize_t len; - struct adapter *adap = to_net_dev(d)->priv; /* Synchronize with ioctls that may shut down the device */ rtnl_lock(); - len = (*format) (adap, buf); + len = (*format) (to_net_dev(d), buf); rtnl_unlock(); return len; } static ssize_t attr_store(struct device *d, struct device_attribute *attr, const char *buf, size_t len, - ssize_t(*set) (struct adapter *, unsigned int), + ssize_t(*set) (struct net_device *, unsigned int), unsigned int min_val, unsigned int max_val) { char *endp; ssize_t ret; unsigned int val; - struct adapter *adap = to_net_dev(d)->priv; if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -464,7 +462,7 @@ static ssize_t attr_store(struct device *d, struct device_attribute *attr, return -EINVAL; rtnl_lock(); - ret = (*set) (adap, val); + ret = (*set) (to_net_dev(d), val); if (!ret) ret = len; rtnl_unlock(); @@ -472,8 +470,9 @@ static ssize_t attr_store(struct device *d, struct device_attribute *attr, } #define CXGB3_SHOW(name, val_expr) \ -static ssize_t format_##name(struct adapter *adap, char *buf) \ +static ssize_t format_##name(struct net_device *dev, char *buf) \ { \ + struct adapter *adap = dev->priv; \ return sprintf(buf, "%u\n", val_expr); \ } \ static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ @@ -482,8 +481,10 @@ static ssize_t show_##name(struct device *d, struct device_attribute *attr, \ return attr_show(d, attr, buf, format_##name); \ } -static ssize_t set_nfilters(struct adapter *adap, unsigned int val) +static ssize_t set_nfilters(struct net_device *dev, unsigned int val) { + struct adapter *adap = dev->priv; + if (adap->flags & FULL_INIT_DONE) return -EBUSY; if (val && adap->params.rev == 0) @@ -500,8 +501,10 @@ static ssize_t store_nfilters(struct device *d, struct device_attribute *attr, return attr_store(d, attr, buf, len, set_nfilters, 0, ~0); } -static ssize_t set_nservers(struct adapter *adap, unsigned int val) +static ssize_t set_nservers(struct net_device *dev, unsigned int val) { + struct adapter *adap = dev->priv; + if (adap->flags & FULL_INIT_DONE) return -EBUSY; if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters) @@ -1549,32 +1552,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) return -EFAULT; switch (cmd) { - case CHELSIO_SETREG:{ - struct ch_reg edata; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - if ((edata.addr & 3) != 0 - || edata.addr >= adapter->mmio_len) - return -EINVAL; - writel(edata.val, adapter->regs + edata.addr); - break; - } - case CHELSIO_GETREG:{ - struct ch_reg edata; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - if ((edata.addr & 3) != 0 - || edata.addr >= adapter->mmio_len) - return -EINVAL; - edata.val = readl(adapter->regs + edata.addr); - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - break; - } case CHELSIO_SET_QSET_PARAMS:{ int i; struct qset_params *q; @@ -1838,10 +1815,10 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) return -EINVAL; /* - * Version scheme: - * bits 0..9: chip version - * bits 10..15: chip revision - */ + * Version scheme: + * bits 0..9: chip version + * bits 10..15: chip revision + */ t.version = 3 | (adapter->params.rev << 10); if (copy_to_user(useraddr, &t, sizeof(t))) return -EFAULT; @@ -1890,20 +1867,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) t.trace_rx); break; } - case CHELSIO_SET_PKTSCHED:{ - struct ch_pktsched_params p; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - if (!adapter->open_device_map) - return -EAGAIN; /* uP and SGE must be running */ - if (copy_from_user(&p, useraddr, sizeof(p))) - return -EFAULT; - send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max, - p.binding); - break; - - } default: return -EOPNOTSUPP; } diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index b2cf5f6feb4..f6ed033efb5 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -160,14 +160,16 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter, int i; for_each_port(adapter, i) { - const struct vlan_group *grp; + struct vlan_group *grp; struct net_device *dev = adapter->port[i]; const struct port_info *p = netdev_priv(dev); if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) { if (vlan && vlan != VLAN_VID_MASK) { grp = p->vlan_grp; - dev = grp ? grp->vlan_devices[vlan] : NULL; + dev = NULL; + if (grp) + dev = vlan_group_get_device(grp, vlan); } else while (dev->master) dev = dev->master; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 3f2cf8a07c6..c23783432e5 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -45,9 +45,25 @@ #define USE_GTS 0 #define SGE_RX_SM_BUF_SIZE 1536 + +/* + * If USE_RX_PAGE is defined, the small freelist populated with (partial) + * pages instead of skbs. Pages are carved up into RX_PAGE_SIZE chunks (must + * be a multiple of the host page size). + */ +#define USE_RX_PAGE +#define RX_PAGE_SIZE 2048 + +/* + * skb freelist packets are copied into a new skb (and the freelist one is + * reused) if their len is <= + */ #define SGE_RX_COPY_THRES 256 -# define SGE_RX_DROP_THRES 16 +/* + * Minimum number of freelist entries before we start dropping TUNNEL frames. + */ +#define SGE_RX_DROP_THRES 16 /* * Period of the Tx buffer reclaim timer. This timer does not need to run @@ -85,7 +101,10 @@ struct tx_sw_desc { /* SW state per Tx descriptor */ }; struct rx_sw_desc { /* SW state per Rx descriptor */ - struct sk_buff *skb; + union { + struct sk_buff *skb; + struct sge_fl_page page; + } t; DECLARE_PCI_UNMAP_ADDR(dma_addr); }; @@ -105,6 +124,15 @@ struct unmap_info { /* packet unmapping info, overlays skb->cb */ }; /* + * Holds unmapping information for Tx packets that need deferred unmapping. + * This structure lives at skb->head and must be allocated by callers. + */ +struct deferred_unmap_info { + struct pci_dev *pdev; + dma_addr_t addr[MAX_SKB_FRAGS + 1]; +}; + +/* * Maps a number of flits to the number of Tx descriptors that can hold them. * The formula is * @@ -252,10 +280,13 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q, struct pci_dev *pdev = adapter->pdev; unsigned int cidx = q->cidx; + const int need_unmap = need_skb_unmap() && + q->cntxt_id >= FW_TUNNEL_SGEEC_START; + d = &q->sdesc[cidx]; while (n--) { if (d->skb) { /* an SGL is present */ - if (need_skb_unmap()) + if (need_unmap) unmap_skb(d->skb, q, cidx, pdev); if (d->skb->priority == cidx) kfree_skb(d->skb); @@ -320,16 +351,27 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr), q->buf_size, PCI_DMA_FROMDEVICE); - kfree_skb(d->skb); - d->skb = NULL; + + if (q->buf_size != RX_PAGE_SIZE) { + kfree_skb(d->t.skb); + d->t.skb = NULL; + } else { + if (d->t.page.frag.page) + put_page(d->t.page.frag.page); + d->t.page.frag.page = NULL; + } if (++cidx == q->size) cidx = 0; } + + if (q->page.frag.page) + put_page(q->page.frag.page); + q->page.frag.page = NULL; } /** * add_one_rx_buf - add a packet buffer to a free-buffer list - * @skb: the buffer to add + * @va: va of the buffer to add * @len: the buffer length * @d: the HW Rx descriptor to write * @sd: the SW Rx descriptor to write @@ -339,14 +381,13 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q) * Add a buffer of the given length to the supplied HW and SW Rx * descriptors. */ -static inline void add_one_rx_buf(struct sk_buff *skb, unsigned int len, +static inline void add_one_rx_buf(unsigned char *va, unsigned int len, struct rx_desc *d, struct rx_sw_desc *sd, unsigned int gen, struct pci_dev *pdev) { dma_addr_t mapping; - sd->skb = skb; - mapping = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE); + mapping = pci_map_single(pdev, va, len, PCI_DMA_FROMDEVICE); pci_unmap_addr_set(sd, dma_addr, mapping); d->addr_lo = cpu_to_be32(mapping); @@ -371,14 +412,47 @@ static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp) { struct rx_sw_desc *sd = &q->sdesc[q->pidx]; struct rx_desc *d = &q->desc[q->pidx]; + struct sge_fl_page *p = &q->page; while (n--) { - struct sk_buff *skb = alloc_skb(q->buf_size, gfp); + unsigned char *va; - if (!skb) - break; + if (unlikely(q->buf_size != RX_PAGE_SIZE)) { + struct sk_buff *skb = alloc_skb(q->buf_size, gfp); + + if (!skb) { + q->alloc_failed++; + break; + } + va = skb->data; + sd->t.skb = skb; + } else { + if (!p->frag.page) { + p->frag.page = alloc_pages(gfp, 0); + if (unlikely(!p->frag.page)) { + q->alloc_failed++; + break; + } else { + p->frag.size = RX_PAGE_SIZE; + p->frag.page_offset = 0; + p->va = page_address(p->frag.page); + } + } + + memcpy(&sd->t, p, sizeof(*p)); + va = p->va; + + p->frag.page_offset += RX_PAGE_SIZE; + BUG_ON(p->frag.page_offset > PAGE_SIZE); + p->va += RX_PAGE_SIZE; + if (p->frag.page_offset == PAGE_SIZE) + p->frag.page = NULL; + else + get_page(p->frag.page); + } + + add_one_rx_buf(va, q->buf_size, d, sd, q->gen, adap->pdev); - add_one_rx_buf(skb, q->buf_size, d, sd, q->gen, adap->pdev); d++; sd++; if (++q->pidx == q->size) { @@ -413,7 +487,7 @@ static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, struct rx_desc *from = &q->desc[idx]; struct rx_desc *to = &q->desc[q->pidx]; - q->sdesc[q->pidx] = q->sdesc[idx]; + memcpy(&q->sdesc[q->pidx], &q->sdesc[idx], sizeof(struct rx_sw_desc)); to->addr_lo = from->addr_lo; /* already big endian */ to->addr_hi = from->addr_hi; /* likewise */ wmb(); @@ -446,7 +520,7 @@ static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q, * of the SW ring. */ static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, - size_t sw_size, dma_addr_t *phys, void *metadata) + size_t sw_size, dma_addr_t * phys, void *metadata) { size_t len = nelem * elem_size; void *s = NULL; @@ -576,61 +650,6 @@ static inline unsigned int flits_to_desc(unsigned int n) } /** - * get_packet - return the next ingress packet buffer from a free list - * @adap: the adapter that received the packet - * @fl: the SGE free list holding the packet - * @len: the packet length including any SGE padding - * @drop_thres: # of remaining buffers before we start dropping packets - * - * Get the next packet from a free list and complete setup of the - * sk_buff. If the packet is small we make a copy and recycle the - * original buffer, otherwise we use the original buffer itself. If a - * positive drop threshold is supplied packets are dropped and their - * buffers recycled if (a) the number of remaining buffers is under the - * threshold and the packet is too big to copy, or (b) the packet should - * be copied but there is no memory for the copy. - */ -static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, - unsigned int len, unsigned int drop_thres) -{ - struct sk_buff *skb = NULL; - struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; - - prefetch(sd->skb->data); - - if (len <= SGE_RX_COPY_THRES) { - skb = alloc_skb(len, GFP_ATOMIC); - if (likely(skb != NULL)) { - __skb_put(skb, len); - pci_dma_sync_single_for_cpu(adap->pdev, - pci_unmap_addr(sd, - dma_addr), - len, PCI_DMA_FROMDEVICE); - memcpy(skb->data, sd->skb->data, len); - pci_dma_sync_single_for_device(adap->pdev, - pci_unmap_addr(sd, - dma_addr), - len, PCI_DMA_FROMDEVICE); - } else if (!drop_thres) - goto use_orig_buf; - recycle: - recycle_rx_buf(adap, fl, fl->cidx); - return skb; - } - - if (unlikely(fl->credits < drop_thres)) - goto recycle; - - use_orig_buf: - pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr), - fl->buf_size, PCI_DMA_FROMDEVICE); - skb = sd->skb; - skb_put(skb, len); - __refill_fl(adap, fl); - return skb; -} - -/** * get_imm_packet - return the next ingress packet buffer from a response * @resp: the response descriptor containing the packet data * @@ -1227,6 +1246,50 @@ int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb) } /** + * deferred_unmap_destructor - unmap a packet when it is freed + * @skb: the packet + * + * This is the packet destructor used for Tx packets that need to remain + * mapped until they are freed rather than until their Tx descriptors are + * freed. + */ +static void deferred_unmap_destructor(struct sk_buff *skb) +{ + int i; + const dma_addr_t *p; + const struct skb_shared_info *si; + const struct deferred_unmap_info *dui; + const struct unmap_info *ui = (struct unmap_info *)skb->cb; + + dui = (struct deferred_unmap_info *)skb->head; + p = dui->addr; + + if (ui->len) + pci_unmap_single(dui->pdev, *p++, ui->len, PCI_DMA_TODEVICE); + + si = skb_shinfo(skb); + for (i = 0; i < si->nr_frags; i++) + pci_unmap_page(dui->pdev, *p++, si->frags[i].size, + PCI_DMA_TODEVICE); +} + +static void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev, + const struct sg_ent *sgl, int sgl_flits) +{ + dma_addr_t *p; + struct deferred_unmap_info *dui; + + dui = (struct deferred_unmap_info *)skb->head; + dui->pdev = pdev; + for (p = dui->addr; sgl_flits >= 3; sgl++, sgl_flits -= 3) { + *p++ = be64_to_cpu(sgl->addr[0]); + *p++ = be64_to_cpu(sgl->addr[1]); + } + if (sgl_flits) + *p = be64_to_cpu(sgl->addr[0]); +} + +/** * write_ofld_wr - write an offload work request * @adap: the adapter * @skb: the packet to send @@ -1262,8 +1325,11 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw, adap->pdev); - if (need_skb_unmap()) + if (need_skb_unmap()) { + setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); + skb->destructor = deferred_unmap_destructor; ((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw; + } write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, from->wr_hi, from->wr_lo); @@ -1617,7 +1683,6 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad); struct port_info *pi; - rq->eth_pkts++; skb_pull(skb, sizeof(*p) + pad); skb->dev = adap->port[p->iff]; skb->dev->last_rx = jiffies; @@ -1645,6 +1710,85 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, netif_rx(skb); } +#define SKB_DATA_SIZE 128 + +static void skb_data_init(struct sk_buff *skb, struct sge_fl_page *p, + unsigned int len) +{ + skb->len = len; + if (len <= SKB_DATA_SIZE) { + memcpy(skb->data, p->va, len); + skb->tail += len; + put_page(p->frag.page); + } else { + memcpy(skb->data, p->va, SKB_DATA_SIZE); + skb_shinfo(skb)->frags[0].page = p->frag.page; + skb_shinfo(skb)->frags[0].page_offset = + p->frag.page_offset + SKB_DATA_SIZE; + skb_shinfo(skb)->frags[0].size = len - SKB_DATA_SIZE; + skb_shinfo(skb)->nr_frags = 1; + skb->data_len = len - SKB_DATA_SIZE; + skb->tail += SKB_DATA_SIZE; + skb->truesize += skb->data_len; + } +} + +/** +* get_packet - return the next ingress packet buffer from a free list +* @adap: the adapter that received the packet +* @fl: the SGE free list holding the packet +* @len: the packet length including any SGE padding +* @drop_thres: # of remaining buffers before we start dropping packets +* +* Get the next packet from a free list and complete setup of the +* sk_buff. If the packet is small we make a copy and recycle the +* original buffer, otherwise we use the original buffer itself. If a +* positive drop threshold is supplied packets are dropped and their +* buffers recycled if (a) the number of remaining buffers is under the +* threshold and the packet is too big to copy, or (b) the packet should +* be copied but there is no memory for the copy. +*/ +static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl, + unsigned int len, unsigned int drop_thres) +{ + struct sk_buff *skb = NULL; + struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + + prefetch(sd->t.skb->data); + + if (len <= SGE_RX_COPY_THRES) { + skb = alloc_skb(len, GFP_ATOMIC); + if (likely(skb != NULL)) { + struct rx_desc *d = &fl->desc[fl->cidx]; + dma_addr_t mapping = + (dma_addr_t)((u64) be32_to_cpu(d->addr_hi) << 32 | + be32_to_cpu(d->addr_lo)); + + __skb_put(skb, len); + pci_dma_sync_single_for_cpu(adap->pdev, mapping, len, + PCI_DMA_FROMDEVICE); + memcpy(skb->data, sd->t.skb->data, len); + pci_dma_sync_single_for_device(adap->pdev, mapping, len, + PCI_DMA_FROMDEVICE); + } else if (!drop_thres) + goto use_orig_buf; +recycle: + recycle_rx_buf(adap, fl, fl->cidx); + return skb; + } + + if (unlikely(fl->credits < drop_thres)) + goto recycle; + +use_orig_buf: + pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr), + fl->buf_size, PCI_DMA_FROMDEVICE); + skb = sd->t.skb; + skb_put(skb, len); + __refill_fl(adap, fl); + return skb; +} + /** * handle_rsp_cntrl_info - handles control information in a response * @qs: the queue set corresponding to the response @@ -1767,7 +1911,7 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->next_holdoff = q->holdoff_tmr; while (likely(budget_left && is_new_response(r, q))) { - int eth, ethpad = 0; + int eth, ethpad = 2; struct sk_buff *skb = NULL; u32 len, flags = ntohl(r->flags); u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val; @@ -1794,18 +1938,56 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, break; } q->imm_data++; + ethpad = 0; } else if ((len = ntohl(r->len_cq)) != 0) { - struct sge_fl *fl; + struct sge_fl *fl = + (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; + + if (fl->buf_size == RX_PAGE_SIZE) { + struct rx_sw_desc *sd = &fl->sdesc[fl->cidx]; + struct sge_fl_page *p = &sd->t.page; + + prefetch(p->va); + prefetch(p->va + L1_CACHE_BYTES); + + __refill_fl(adap, fl); + + pci_unmap_single(adap->pdev, + pci_unmap_addr(sd, dma_addr), + fl->buf_size, + PCI_DMA_FROMDEVICE); + + if (eth) { + if (unlikely(fl->credits < + SGE_RX_DROP_THRES)) + goto eth_recycle; + + skb = alloc_skb(SKB_DATA_SIZE, + GFP_ATOMIC); + if (unlikely(!skb)) { +eth_recycle: + q->rx_drops++; + recycle_rx_buf(adap, fl, + fl->cidx); + goto eth_done; + } + } else { + skb = alloc_skb(SKB_DATA_SIZE, + GFP_ATOMIC); + if (unlikely(!skb)) + goto no_mem; + } + + skb_data_init(skb, p, G_RSPD_LEN(len)); +eth_done: + fl->credits--; + q->eth_pkts++; + } else { + fl->credits--; + skb = get_packet(adap, fl, G_RSPD_LEN(len), + eth ? SGE_RX_DROP_THRES : 0); + } - fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0]; - fl->credits--; - skb = get_packet(adap, fl, G_RSPD_LEN(len), - eth ? SGE_RX_DROP_THRES : 0); - if (!skb) - q->rx_drops++; - else if (r->rss_hdr.opcode == CPL_TRACE_PKT) - __skb_pull(skb, 2); - ethpad = 2; if (++fl->cidx == fl->size) fl->cidx = 0; } else @@ -1829,18 +2011,23 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs, q->credits = 0; } - if (likely(skb != NULL)) { + if (skb) { + /* Preserve the RSS info in csum & priority */ + skb->csum = rss_hi; + skb->priority = rss_lo; + if (eth) rx_eth(adap, q, skb, ethpad); else { - /* Preserve the RSS info in csum & priority */ - skb->csum = rss_hi; - skb->priority = rss_lo; - ngathered = rx_offload(&adap->tdev, q, skb, - offload_skbs, ngathered); + if (unlikely(r->rss_hdr.opcode == + CPL_TRACE_PKT)) + __skb_pull(skb, ethpad); + + ngathered = rx_offload(&adap->tdev, q, + skb, offload_skbs, + ngathered); } } - --budget_left; } @@ -2320,10 +2507,23 @@ static void sge_timer_cb(unsigned long data) &adap->sge.qs[0].rspq.lock; if (spin_trylock_irq(lock)) { if (!napi_is_scheduled(qs->netdev)) { + u32 status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS); + if (qs->fl[0].credits < qs->fl[0].size) __refill_fl(adap, &qs->fl[0]); if (qs->fl[1].credits < qs->fl[1].size) __refill_fl(adap, &qs->fl[1]); + + if (status & (1 << qs->rspq.cntxt_id)) { + qs->rspq.starved++; + if (qs->rspq.credits) { + refill_rspq(adap, &qs->rspq, 1); + qs->rspq.credits--; + qs->rspq.restarted++; + t3_write_reg(adap, A_SG_RSPQ_FL_STATUS, + 1 << qs->rspq.cntxt_id); + } + } } spin_unlock_irq(lock); } @@ -2432,13 +2632,21 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3); if (ntxq == 1) { +#ifdef USE_RX_PAGE + q->fl[0].buf_size = RX_PAGE_SIZE; +#else q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 + sizeof(struct cpl_rx_pkt); +#endif q->fl[1].buf_size = MAX_FRAME_SIZE + 2 + sizeof(struct cpl_rx_pkt); } else { +#ifdef USE_RX_PAGE + q->fl[0].buf_size = RX_PAGE_SIZE; +#else q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + sizeof(struct cpl_rx_data); +#endif q->fl[1].buf_size = (16 * 1024) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); } @@ -2632,7 +2840,7 @@ void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p) q->polling = adap->params.rev > 0; q->coalesce_usecs = 5; q->rspq_size = 1024; - q->fl_size = 4096; + q->fl_size = 1024; q->jumbo_size = 512; q->txq_size[TXQ_ETH] = 1024; q->txq_size[TXQ_OFLD] = 1024; diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 365a7f5b1f9..eaa7a2e89a3 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -884,11 +884,13 @@ int t3_check_fw_version(struct adapter *adapter) major = G_FW_VERSION_MAJOR(vers); minor = G_FW_VERSION_MINOR(vers); - if (type == FW_VERSION_T3 && major == 3 && minor == 1) + if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR && + minor == FW_VERSION_MINOR) return 0; CH_ERR(adapter, "found wrong FW version(%u.%u), " - "driver needs version 3.1\n", major, minor); + "driver needs version %u.%u\n", major, minor, + FW_VERSION_MAJOR, FW_VERSION_MINOR); return -EINVAL; } diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index 2b67dd523cc..82278f85025 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -35,5 +35,7 @@ #define DRV_DESC "Chelsio T3 Network Driver" #define DRV_NAME "cxgb3" /* Driver version */ -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.0-ko" +#define FW_VERSION_MAJOR 3 +#define FW_VERSION_MINOR 2 #endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/de600.c b/drivers/net/de600.c index 8396e411f1c..e547ce14eef 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -38,12 +38,6 @@ static const char version[] = "de600.c: $Revision: 1.41-2.5 $, Bjorn Ekwall (bj /* Add more time here if your adapter won't work OK: */ #define DE600_SLOW_DOWN udelay(delay_time) - /* - * If you still have trouble reading/writing to the adapter, - * modify the following "#define": (see <asm/io.h> for more info) -#define REALLY_SLOW_IO - */ - /* use 0 for production, 1 for verification, >2 for debug */ #ifdef DE600_DEBUG #define PRINTK(x) if (de600_debug >= 2) printk x diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 98215fdd7d1..1d08e937af8 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -376,7 +376,7 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter) uint16_t vid = adapter->hw.mng_cookie.vlan_id; uint16_t old_vid = adapter->mng_vlan_id; if (adapter->vlgrp) { - if (!adapter->vlgrp->vlan_devices[vid]) { + if (!vlan_group_get_device(adapter->vlgrp, vid)) { if (adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) { e1000_vlan_rx_add_vid(netdev, vid); @@ -386,7 +386,7 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter) if ((old_vid != (uint16_t)E1000_MNG_VLAN_NONE) && (vid != old_vid) && - !adapter->vlgrp->vlan_devices[old_vid]) + !vlan_group_get_device(adapter->vlgrp, old_vid)) e1000_vlan_rx_kill_vid(netdev, old_vid); } else adapter->mng_vlan_id = vid; @@ -1482,7 +1482,7 @@ e1000_close(struct net_device *netdev) if ((adapter->hw.mng_cookie.status & E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) && !(adapter->vlgrp && - adapter->vlgrp->vlan_devices[adapter->mng_vlan_id])) { + vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id))) { e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); } @@ -4998,10 +4998,7 @@ e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) uint32_t vfta, index; e1000_irq_disable(adapter); - - if (adapter->vlgrp) - adapter->vlgrp->vlan_devices[vid] = NULL; - + vlan_group_set_device(adapter->vlgrp, vid, NULL); e1000_irq_enable(adapter); if ((adapter->hw.mng_cookie.status & @@ -5027,7 +5024,7 @@ e1000_restore_vlan(struct e1000_adapter *adapter) if (adapter->vlgrp) { uint16_t vid; for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { - if (!adapter->vlgrp->vlan_devices[vid]) + if (!vlan_group_get_device(adapter->vlgrp, vid)) continue; e1000_vlan_rx_add_vid(adapter->netdev, vid); } diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 88ad1c8bcee..0e4042bc0a4 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -1939,8 +1939,7 @@ static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) int index; u64 hret; - if (port->vgrp) - port->vgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(port->vgrp, vid, NULL); cb1 = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!cb1) { diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index a363148d019..46e1697d9cf 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -839,7 +839,7 @@ enum { NV_MSIX_INT_DISABLED, NV_MSIX_INT_ENABLED }; -static int msix = NV_MSIX_INT_ENABLED; +static int msix = NV_MSIX_INT_DISABLED; /* * DMA 64bit @@ -3104,13 +3104,17 @@ static int nv_napi_poll(struct net_device *dev, int *budget) struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); unsigned long flags; + int retcode; - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { pkts = nv_rx_process(dev, limit); - else + retcode = nv_alloc_rx(dev); + } else { pkts = nv_rx_process_optimized(dev, limit); + retcode = nv_alloc_rx_optimized(dev); + } - if (nv_alloc_rx(dev)) { + if (retcode) { spin_lock_irqsave(&np->lock, flags); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -5370,19 +5374,19 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 1f83988a6a6..d981d4c41dd 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -1132,8 +1132,7 @@ static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid) spin_lock_irqsave(&priv->rxlock, flags); - if (priv->vlgrp) - priv->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(priv->vlgrp, vid, NULL); spin_unlock_irqrestore(&priv->rxlock, flags); } diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 0c368288934..afc2ec72529 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -2213,8 +2213,7 @@ ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) ixgb_irq_disable(adapter); - if(adapter->vlgrp) - adapter->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(adapter->vlgrp, vid, NULL); ixgb_irq_enable(adapter); @@ -2234,7 +2233,7 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter) if(adapter->vlgrp) { uint16_t vid; for(vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) { - if(!adapter->vlgrp->vlan_devices[vid]) + if(!vlan_group_get_device(adapter->vlgrp, vid)) continue; ixgb_vlan_rx_add_vid(adapter->netdev, vid); } diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index ea392f2a5aa..452863d5d49 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -384,7 +384,7 @@ struct i596_private { struct device *dev; }; -static char init_setup[] = +static const char init_setup[] = { 0x8E, /* length, prefetch on */ 0xC8, /* fifo to 8, monitor off */ @@ -683,7 +683,7 @@ static int init_i596_mem(struct net_device *dev) enable_irq(dev->irq); /* enable IRQs from LAN */ DEB(DEB_INIT, printk("%s: queuing CmdConfigure\n", dev->name)); - memcpy(lp->cf_cmd.i596_config, init_setup, 14); + memcpy(lp->cf_cmd.i596_config, init_setup, sizeof(init_setup)); lp->cf_cmd.cmd.command = CmdConfigure; CHECK_WBACK(lp, &(lp->cf_cmd), sizeof(struct cf_cmd)); i596_add_cmd(dev, &lp->cf_cmd.cmd); @@ -1156,32 +1156,12 @@ static int __devinit i82596_probe(struct net_device *dev, dma_addr_t dma_addr; /* This lot is ensure things have been cache line aligned. */ - if (sizeof(struct i596_rfd) != 32) { - printk("82596: sizeof(struct i596_rfd) = %d\n", - (int)sizeof(struct i596_rfd)); - return -ENODEV; - } - if ((sizeof(struct i596_rbd) % 32) != 0) { - printk("82596: sizeof(struct i596_rbd) = %d\n", - (int)sizeof(struct i596_rbd)); - return -ENODEV; - } - if ((sizeof(struct tx_cmd) % 32) != 0) { - printk("82596: sizeof(struct tx_cmd) = %d\n", - (int)sizeof(struct tx_cmd)); - return -ENODEV; - } - if (sizeof(struct i596_tbd) != 32) { - printk("82596: sizeof(struct i596_tbd) = %d\n", - (int)sizeof(struct i596_tbd)); - return -ENODEV; - } + BUILD_BUG_ON(sizeof(struct i596_rfd) != 32); + BUILD_BUG_ON(sizeof(struct i596_rbd) & 31); + BUILD_BUG_ON(sizeof(struct tx_cmd) & 31); + BUILD_BUG_ON(sizeof(struct i596_tbd) != 32); #ifndef __LP64__ - if (sizeof(struct i596_private) > 4096) { - printk("82596: sizeof(struct i596_private) = %d\n", - (int)sizeof(struct i596_private)); - return -ENODEV; - } + BUILD_BUG_ON(sizeof(struct i596_private) > 4096); #endif if (!dev->base_addr || !dev->irq) diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index d98e53efa2e..1ee27c360a4 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -147,13 +147,13 @@ static void mv643xx_eth_rx_refill_descs(struct net_device *dev) int unaligned; while (mp->rx_desc_count < mp->rx_ring_size) { - skb = dev_alloc_skb(ETH_RX_SKB_SIZE + ETH_DMA_ALIGN); + skb = dev_alloc_skb(ETH_RX_SKB_SIZE + dma_get_cache_alignment()); if (!skb) break; mp->rx_desc_count++; - unaligned = (u32)skb->data & (ETH_DMA_ALIGN - 1); + unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1); if (unaligned) - skb_reserve(skb, ETH_DMA_ALIGN - unaligned); + skb_reserve(skb, dma_get_cache_alignment() - unaligned); pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT; pkt_info.byte_cnt = ETH_RX_SKB_SIZE; pkt_info.buf_ptr = dma_map_single(NULL, skb->data, @@ -787,6 +787,12 @@ static int mv643xx_eth_open(struct net_device *dev) unsigned int size; int err; + /* Clear any pending ethernet port interrupts */ + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + /* wait for previous write to complete */ + mv_read (MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)); + err = request_irq(dev->irq, mv643xx_eth_int_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev); if (err) { @@ -875,10 +881,6 @@ static int mv643xx_eth_open(struct net_device *dev) mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */ - /* Clear any pending ethernet port interrupts */ - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); - eth_port_start(dev); /* Interrupt Coalescing */ @@ -1309,7 +1311,7 @@ static void mv643xx_init_ethtool_cmd(struct net_device *dev, int phy_address, static int mv643xx_eth_probe(struct platform_device *pdev) { struct mv643xx_eth_platform_data *pd; - int port_num = pdev->id; + int port_num; struct mv643xx_private *mp; struct net_device *dev; u8 *p; @@ -1319,6 +1321,12 @@ static int mv643xx_eth_probe(struct platform_device *pdev) int duplex = DUPLEX_HALF; int speed = 0; /* default to auto-negotiation */ + pd = pdev->dev.platform_data; + if (pd == NULL) { + printk(KERN_ERR "No mv643xx_eth_platform_data\n"); + return -ENODEV; + } + dev = alloc_etherdev(sizeof(struct mv643xx_private)); if (!dev) return -ENOMEM; @@ -1331,8 +1339,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) BUG_ON(!res); dev->irq = res->start; - mp->port_num = port_num; - dev->open = mv643xx_eth_open; dev->stop = mv643xx_eth_stop; dev->hard_start_xmit = mv643xx_eth_start_xmit; @@ -1373,39 +1379,40 @@ static int mv643xx_eth_probe(struct platform_device *pdev) spin_lock_init(&mp->lock); + port_num = pd->port_number; + /* set default config values */ eth_port_uc_addr_get(dev, dev->dev_addr); mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE; mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE; - pd = pdev->dev.platform_data; - if (pd) { - if (pd->mac_addr) - memcpy(dev->dev_addr, pd->mac_addr, 6); - - if (pd->phy_addr || pd->force_phy_addr) - ethernet_phy_set(port_num, pd->phy_addr); + if (is_valid_ether_addr(pd->mac_addr)) + memcpy(dev->dev_addr, pd->mac_addr, 6); - if (pd->rx_queue_size) - mp->rx_ring_size = pd->rx_queue_size; + if (pd->phy_addr || pd->force_phy_addr) + ethernet_phy_set(port_num, pd->phy_addr); - if (pd->tx_queue_size) - mp->tx_ring_size = pd->tx_queue_size; + if (pd->rx_queue_size) + mp->rx_ring_size = pd->rx_queue_size; - if (pd->tx_sram_size) { - mp->tx_sram_size = pd->tx_sram_size; - mp->tx_sram_addr = pd->tx_sram_addr; - } + if (pd->tx_queue_size) + mp->tx_ring_size = pd->tx_queue_size; - if (pd->rx_sram_size) { - mp->rx_sram_size = pd->rx_sram_size; - mp->rx_sram_addr = pd->rx_sram_addr; - } + if (pd->tx_sram_size) { + mp->tx_sram_size = pd->tx_sram_size; + mp->tx_sram_addr = pd->tx_sram_addr; + } - duplex = pd->duplex; - speed = pd->speed; + if (pd->rx_sram_size) { + mp->rx_sram_size = pd->rx_sram_size; + mp->rx_sram_addr = pd->rx_sram_addr; } + duplex = pd->duplex; + speed = pd->speed; + + mp->port_num = port_num; + /* Hook up MII support for ethtool */ mp->mii.dev = dev; mp->mii.mdio_read = mv643xx_mdio_read; diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 33c5fafdbbd..7d4e90cf49e 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -9,6 +9,8 @@ #include <linux/mv643xx.h> +#include <asm/dma-mapping.h> + /* Checksum offload for Tx works for most packets, but * fails if previous packet sent did not use hw csum */ @@ -42,23 +44,12 @@ #define MAX_DESCS_PER_SKB 1 #endif -/* - * The MV643XX HW requires 8-byte alignment. However, when I/O - * is non-cache-coherent, we need to ensure that the I/O buffers - * we use don't share cache lines with other data. - */ -#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_NOT_COHERENT_CACHE) -#define ETH_DMA_ALIGN L1_CACHE_BYTES -#else -#define ETH_DMA_ALIGN 8 -#endif - #define ETH_VLAN_HLEN 4 #define ETH_FCS_LEN 4 #define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */ #define ETH_WRAPPER_LEN (ETH_HW_IP_ALIGN + ETH_HLEN + \ ETH_VLAN_HLEN + ETH_FCS_LEN) -#define ETH_RX_SKB_SIZE (dev->mtu + ETH_WRAPPER_LEN + ETH_DMA_ALIGN) +#define ETH_RX_SKB_SIZE (dev->mtu + ETH_WRAPPER_LEN + dma_get_cache_alignment()) #define ETH_RX_QUEUES_ENABLED (1 << 0) /* use only Q0 for receive */ #define ETH_TX_QUEUES_ENABLED (1 << 0) /* use only Q0 for transmit */ diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 030924fb1ab..ac02b3b60f9 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1,7 +1,7 @@ /************************************************************************* * myri10ge.c: Myricom Myri-10G Ethernet driver. * - * Copyright (C) 2005, 2006 Myricom, Inc. + * Copyright (C) 2005 - 2007 Myricom, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -16,17 +16,17 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. * * * If the eeprom on your board is not recent enough, you will need to get a @@ -181,6 +181,7 @@ struct myri10ge_priv { int intr_coal_delay; __be32 __iomem *intr_coal_delay_ptr; int mtrr; + int wc_enabled; int wake_queue; int stop_queue; int down_cnt; @@ -195,6 +196,10 @@ struct myri10ge_priv { char *fw_name; char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE]; char fw_version[128]; + int fw_ver_major; + int fw_ver_minor; + int fw_ver_tiny; + int adopted_rx_filter_bug; u8 mac_addr[6]; /* eeprom mac address */ unsigned long serial_number; int vendor_specific_offset; @@ -447,7 +452,6 @@ myri10ge_validate_firmware(struct myri10ge_priv *mgp, struct mcp_gen_header *hdr) { struct device *dev = &mgp->pdev->dev; - int major, minor; /* check firmware type */ if (ntohl(hdr->mcp_type) != MCP_TYPE_ETH) { @@ -458,9 +462,11 @@ myri10ge_validate_firmware(struct myri10ge_priv *mgp, /* save firmware version for ethtool */ strncpy(mgp->fw_version, hdr->version, sizeof(mgp->fw_version)); - sscanf(mgp->fw_version, "%d.%d", &major, &minor); + sscanf(mgp->fw_version, "%d.%d.%d", &mgp->fw_ver_major, + &mgp->fw_ver_minor, &mgp->fw_ver_tiny); - if (!(major == MXGEFW_VERSION_MAJOR && minor == MXGEFW_VERSION_MINOR)) { + if (!(mgp->fw_ver_major == MXGEFW_VERSION_MAJOR + && mgp->fw_ver_minor == MXGEFW_VERSION_MINOR)) { dev_err(dev, "Found firmware version %s\n", mgp->fw_version); dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR, MXGEFW_VERSION_MINOR); @@ -561,6 +567,18 @@ static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp) memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes); status = myri10ge_validate_firmware(mgp, hdr); kfree(hdr); + + /* check to see if adopted firmware has bug where adopting + * it will cause broadcasts to be filtered unless the NIC + * is kept in ALLMULTI mode */ + if (mgp->fw_ver_major == 1 && mgp->fw_ver_minor == 4 && + mgp->fw_ver_tiny >= 4 && mgp->fw_ver_tiny <= 11) { + mgp->adopted_rx_filter_bug = 1; + dev_warn(dev, "Adopting fw %d.%d.%d: " + "working around rx filter bug\n", + mgp->fw_ver_major, mgp->fw_ver_minor, + mgp->fw_ver_tiny); + } return status; } @@ -700,6 +718,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) int status; size_t bytes; u32 len; + struct page *dmatest_page; + dma_addr_t dmatest_bus; /* try to send a reset command to the card to see if it * is alive */ @@ -709,6 +729,11 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) dev_err(&mgp->pdev->dev, "failed reset\n"); return -ENXIO; } + dmatest_page = alloc_page(GFP_KERNEL); + if (!dmatest_page) + return -ENOMEM; + dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE, + DMA_BIDIRECTIONAL); /* Now exchange information about interrupts */ @@ -747,8 +772,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) len = mgp->tx.boundary; - cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus); + cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); cmd.data2 = len * 0x10000; status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0); if (status == 0) @@ -757,8 +782,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) else dev_warn(&mgp->pdev->dev, "DMA read benchmark failed: %d\n", status); - cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus); + cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); cmd.data2 = len * 0x1; status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0); if (status == 0) @@ -768,8 +793,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) dev_warn(&mgp->pdev->dev, "DMA write benchmark failed: %d\n", status); - cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus); - cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus); + cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); cmd.data2 = len * 0x10001; status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0); if (status == 0) @@ -779,6 +804,9 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) dev_warn(&mgp->pdev->dev, "DMA read/write benchmark failed: %d\n", status); + pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL); + put_page(dmatest_page); + memset(mgp->rx_done.entry, 0, bytes); /* reset mcp/driver shared state back to 0 */ @@ -794,6 +822,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr); myri10ge_change_promisc(mgp, 0, 0); myri10ge_change_pause(mgp, mgp->pause); + if (mgp->adopted_rx_filter_bug) + (void)myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1); return status; } @@ -1356,7 +1386,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev, data[i] = ((unsigned long *)&mgp->stats)[i]; data[i++] = (unsigned int)mgp->tx.boundary; - data[i++] = (unsigned int)(mgp->mtrr >= 0); + data[i++] = (unsigned int)mgp->wc_enabled; data[i++] = (unsigned int)mgp->pdev->irq; data[i++] = (unsigned int)mgp->msi_enabled; data[i++] = (unsigned int)mgp->read_dma; @@ -1437,6 +1467,8 @@ static int myri10ge_allocate_rings(struct net_device *dev) status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0); tx_ring_size = cmd.data0; status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0); + if (status != 0) + return status; rx_ring_size = cmd.data0; tx_ring_entries = tx_ring_size / sizeof(struct mcp_kreq_ether_send); @@ -1444,6 +1476,8 @@ static int myri10ge_allocate_rings(struct net_device *dev) mgp->tx.mask = tx_ring_entries - 1; mgp->rx_small.mask = mgp->rx_big.mask = rx_ring_entries - 1; + status = -ENOMEM; + /* allocate the host shadow rings */ bytes = 8 + (MYRI10GE_MAX_SEND_DESC_TSO + 4) @@ -1716,7 +1750,7 @@ static int myri10ge_open(struct net_device *dev) goto abort_with_irq; } - if (myri10ge_wcfifo && mgp->mtrr >= 0) { + if (myri10ge_wcfifo && mgp->wc_enabled) { mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4; mgp->rx_small.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL; @@ -2239,7 +2273,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev) myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1); /* This firmware is known to not support multicast */ - if (!mgp->fw_multicast_support) + if (!mgp->fw_multicast_support || mgp->adopted_rx_filter_bug) return; /* Disable multicast filtering */ @@ -2491,6 +2525,12 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) bridge->vendor, bridge->device); mgp->tx.boundary = 4096; mgp->fw_name = myri10ge_fw_aligned; + } else if (bridge && + bridge->vendor == PCI_VENDOR_ID_SGI && + bridge->device == 0x4002 /* TIOCE pcie-port */ ) { + /* this pcie bridge does not support 4K rdma request */ + mgp->tx.boundary = 2048; + mgp->fw_name = myri10ge_fw_aligned; } } else { if (myri10ge_force_firmware == 1) { @@ -2811,9 +2851,12 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) mgp->board_span = pci_resource_len(pdev, 0); mgp->iomem_base = pci_resource_start(pdev, 0); mgp->mtrr = -1; + mgp->wc_enabled = 0; #ifdef CONFIG_MTRR mgp->mtrr = mtrr_add(mgp->iomem_base, mgp->board_span, MTRR_TYPE_WRCOMB, 1); + if (mgp->mtrr >= 0) + mgp->wc_enabled = 1; #endif /* Hack. need to get rid of these magic numbers */ mgp->sram_size = @@ -2908,7 +2951,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n", (mgp->msi_enabled ? "MSI" : "xPIC"), netdev->irq, mgp->tx.boundary, mgp->fw_name, - (mgp->mtrr >= 0 ? "Enabled" : "Disabled")); + (mgp->wc_enabled ? "Enabled" : "Disabled")); return 0; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index adf29dd6679..c6172a77a6d 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -260,7 +260,7 @@ static const struct { static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_NS, 0x0020, 0x12d9, 0x000c, 0, 0, 0 }, - { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, { } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl); @@ -2024,6 +2024,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); unsigned entry; + unsigned long flags; /* Note: Ordering is important here, set the field with the "ownership" bit last, and only then increment cur_tx. */ @@ -2037,7 +2038,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]); - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); if (!np->hands_off) { np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len); @@ -2056,7 +2057,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_irq(skb); np->stats.tx_dropped++; } - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); dev->trans_start = jiffies; @@ -2222,6 +2223,8 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) pkt_len = (desc_status & DescSizeMask) - 4; if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ if (desc_status & DescMore) { + unsigned long flags; + if (netif_msg_rx_err(np)) printk(KERN_WARNING "%s: Oversized(?) Ethernet " @@ -2236,12 +2239,12 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) * reset procedure documented in * AN-1287. */ - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); reset_rx(dev); reinit_rx(dev); writel(np->ring_dma, ioaddr + RxRingPtr); check_link(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); /* We'll enable RX on exit from this * function. */ @@ -2396,8 +2399,19 @@ static struct net_device_stats *get_stats(struct net_device *dev) #ifdef CONFIG_NET_POLL_CONTROLLER static void natsemi_poll_controller(struct net_device *dev) { + struct netdev_private *np = netdev_priv(dev); + disable_irq(dev->irq); - intr_handler(dev->irq, dev); + + /* + * A real interrupt might have already reached us at this point + * but NAPI might still haven't called us back. As the interrupt + * status register is cleared by reading, we should prevent an + * interrupt loss in this case... + */ + if (!np->intr_status) + intr_handler(dev->irq, dev); + enable_irq(dev->irq); } #endif diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 2807ef400fb..81742e4e561 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h @@ -72,6 +72,8 @@ #define FLASH_SECTOR_SIZE (64 * 1024) #define FLASH_TOTAL_SIZE (NUM_FLASH_SECTORS * FLASH_SECTOR_SIZE) +#define PHAN_VENDOR_ID 0x4040 + #define RCV_DESC_RINGSIZE \ (sizeof(struct rcv_desc) * adapter->max_rx_desc_count) #define STATUS_DESC_RINGSIZE \ @@ -82,7 +84,7 @@ (sizeof(struct netxen_cmd_buffer) * adapter->max_tx_desc_count) #define RCV_BUFFSIZE \ (sizeof(struct netxen_rx_buffer) * rcv_desc->max_rx_desc_count) -#define find_diff_among(a,b,range) ((a)<(b)?((b)-(a)):((b)+(range)-(a))) +#define find_diff_among(a,b,range) ((a)<=(b)?((b)-(a)):((b)+(range)-(a))) #define NETXEN_NETDEV_STATUS 0x1 #define NETXEN_RCV_PRODUCER_OFFSET 0 diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index 6252e9a8727..986ef98db22 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -82,8 +82,7 @@ static const struct netxen_nic_stats netxen_nic_gstrings_stats[] = { #define NETXEN_NIC_STATS_LEN ARRAY_SIZE(netxen_nic_gstrings_stats) static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = { - "Register_Test_offline", "EEPROM_Test_offline", - "Interrupt_Test_offline", "Loopback_Test_offline", + "Register_Test_on_offline", "Link_Test_on_offline" }; @@ -394,19 +393,12 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) } } -static void -netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; - /* options can be added depending upon the mode */ - wol->wolopts = 0; -} - static u32 netxen_nic_test_link(struct net_device *dev) { struct netxen_port *port = netdev_priv(dev); struct netxen_adapter *adapter = port->adapter; __u32 status; + int val; /* read which mode */ if (adapter->ahw.board_type == NETXEN_NIC_GBE) { @@ -415,11 +407,13 @@ static u32 netxen_nic_test_link(struct net_device *dev) NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, &status) != 0) return -EIO; - else - return (netxen_get_phy_link(status)); + else { + val = netxen_get_phy_link(status); + return !val; + } } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { - int val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); - return val == XG_LINK_UP; + val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); + return (val == XG_LINK_UP) ? 0 : 1; } return -EIO; } @@ -606,100 +600,21 @@ netxen_nic_set_pauseparam(struct net_device *dev, static int netxen_nic_reg_test(struct net_device *dev) { - struct netxen_port *port = netdev_priv(dev); - struct netxen_adapter *adapter = port->adapter; - u32 data_read, data_written, save; - __u32 mode; - - /* - * first test the "Read Only" registers by writing which mode - */ - netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode); - if (netxen_get_niu_enable_ge(mode)) { /* GB Mode */ - netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_MII_MGMT_STATUS(port->portnum), - &data_read); - - save = data_read; - if (data_read) - data_written = data_read & NETXEN_NIC_INVALID_DATA; - else - data_written = NETXEN_NIC_INVALID_DATA; - netxen_nic_write_w0(adapter, - NETXEN_NIU_GB_MII_MGMT_STATUS(port-> - portnum), - data_written); - netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_MII_MGMT_STATUS(port->portnum), - &data_read); - - if (data_written == data_read) { - netxen_nic_write_w0(adapter, - NETXEN_NIU_GB_MII_MGMT_STATUS(port-> - portnum), - save); - - return 0; - } - - /* netxen_niu_gb_mii_mgmt_indicators is read only */ - netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE(port-> - portnum), - &data_read); - - save = data_read; - if (data_read) - data_written = data_read & NETXEN_NIC_INVALID_DATA; - else - data_written = NETXEN_NIC_INVALID_DATA; - netxen_nic_write_w0(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE(port-> - portnum), - data_written); - - netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE(port-> - portnum), - &data_read); - - if (data_written == data_read) { - netxen_nic_write_w0(adapter, - NETXEN_NIU_GB_MII_MGMT_INDICATE - (port->portnum), save); - return 0; - } + struct netxen_adapter *adapter = netdev_priv(dev); + u32 data_read, data_written; - /* netxen_niu_gb_interface_status is read only */ - netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_INTERFACE_STATUS(port-> - portnum), - &data_read); + netxen_nic_read_w0(adapter, NETXEN_PCIX_PH_REG(0), &data_read); + if ((data_read & 0xffff) != PHAN_VENDOR_ID) + return 1; - save = data_read; - if (data_read) - data_written = data_read & NETXEN_NIC_INVALID_DATA; - else - data_written = NETXEN_NIC_INVALID_DATA; - netxen_nic_write_w0(adapter, - NETXEN_NIU_GB_INTERFACE_STATUS(port-> - portnum), - data_written); + data_written = (u32)0xa5a5a5a5; - netxen_nic_read_w0(adapter, - NETXEN_NIU_GB_INTERFACE_STATUS(port-> - portnum), - &data_read); + netxen_nic_reg_write(adapter, CRB_SCRATCHPAD_TEST, data_written); + data_read = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_SCRATCHPAD_TEST)); + if (data_written != data_read) + return 1; - if (data_written == data_read) { - netxen_nic_write_w0(adapter, - NETXEN_NIU_GB_INTERFACE_STATUS - (port->portnum), save); - - return 0; - } - } /* GB Mode */ - return 1; + return 0; } static int netxen_nic_diag_test_count(struct net_device *dev) @@ -713,26 +628,20 @@ netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, { if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */ /* link test */ - if (!(data[4] = (u64) netxen_nic_test_link(dev))) + if ((data[1] = (u64) netxen_nic_test_link(dev))) eth_test->flags |= ETH_TEST_FL_FAILED; - if (netif_running(dev)) - dev->stop(dev); - /* register tests */ - if (!(data[0] = netxen_nic_reg_test(dev))) + if ((data[0] = netxen_nic_reg_test(dev))) eth_test->flags |= ETH_TEST_FL_FAILED; - /* other tests pass as of now */ - data[1] = data[2] = data[3] = 1; - if (netif_running(dev)) - dev->open(dev); } else { /* online tests */ - /* link test */ - if (!(data[4] = (u64) netxen_nic_test_link(dev))) + /* register tests */ + if((data[0] = netxen_nic_reg_test(dev))) eth_test->flags |= ETH_TEST_FL_FAILED; - /* other tests pass by default */ - data[0] = data[1] = data[2] = data[3] = 1; + /* link test */ + if ((data[1] = (u64) netxen_nic_test_link(dev))) + eth_test->flags |= ETH_TEST_FL_FAILED; } } @@ -783,7 +692,6 @@ struct ethtool_ops netxen_nic_ethtool_ops = { .get_drvinfo = netxen_nic_get_drvinfo, .get_regs_len = netxen_nic_get_regs_len, .get_regs = netxen_nic_get_regs, - .get_wol = netxen_nic_get_wol, .get_link = ethtool_op_get_link, .get_eeprom_len = netxen_nic_get_eeprom_len, .get_eeprom = netxen_nic_get_eeprom, diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 7195af3e8f3..1be55702557 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -228,7 +228,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) &adapter->ctx_desc_pdev); printk("ctx_desc_phys_addr: 0x%llx\n", - (u64) adapter->ctx_desc_phys_addr); + (unsigned long long) adapter->ctx_desc_phys_addr); if (addr == NULL) { DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); err = -ENOMEM; @@ -242,11 +242,13 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) adapter->cmd_consumer = (uint32_t *) (((char *)addr) + sizeof(struct netxen_ring_ctx)); - addr = pci_alloc_consistent(adapter->ahw.pdev, - sizeof(struct cmd_desc_type0) * - adapter->max_tx_desc_count, - (dma_addr_t *) & hw->cmd_desc_phys_addr); - printk("cmd_desc_phys_addr: 0x%llx\n", (u64) hw->cmd_desc_phys_addr); + addr = netxen_alloc(adapter->ahw.pdev, + sizeof(struct cmd_desc_type0) * + adapter->max_tx_desc_count, + (dma_addr_t *) & hw->cmd_desc_phys_addr, + &adapter->ahw.cmd_desc_pdev); + printk("cmd_desc_phys_addr: 0x%llx\n", + (unsigned long long) hw->cmd_desc_phys_addr); if (addr == NULL) { DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); @@ -507,8 +509,8 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw) void netxen_load_firmware(struct netxen_adapter *adapter) { int i; - long data, size = 0; - long flashaddr = NETXEN_FLASH_BASE, memaddr = NETXEN_PHANTOM_MEM_BASE; + u32 data, size = 0; + u32 flashaddr = NETXEN_FLASH_BASE, memaddr = NETXEN_PHANTOM_MEM_BASE; u64 off; void __iomem *addr; @@ -950,6 +952,7 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) netxen_nic_driver_name); return; } + *ptr32 = le32_to_cpu(*ptr32); ptr32++; addr += sizeof(u32); } diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 2f324366784..586d32b676a 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -38,13 +38,13 @@ #include "netxen_nic_phan_reg.h" struct crb_addr_pair { - long addr; - long data; + u32 addr; + u32 data; }; #define NETXEN_MAX_CRB_XFORM 60 static unsigned int crb_addr_xform[NETXEN_MAX_CRB_XFORM]; -#define NETXEN_ADDR_ERROR ((unsigned long ) 0xffffffff ) +#define NETXEN_ADDR_ERROR (0xffffffff) #define crb_addr_transform(name) \ crb_addr_xform[NETXEN_HW_PX_MAP_CRB_##name] = \ @@ -252,10 +252,10 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) * netxen_decode_crb_addr(0 - utility to translate from internal Phantom CRB * address to external PCI CRB address. */ -unsigned long netxen_decode_crb_addr(unsigned long addr) +u32 netxen_decode_crb_addr(u32 addr) { int i; - unsigned long base_addr, offset, pci_base; + u32 base_addr, offset, pci_base; crb_addr_transform_setup(); @@ -499,7 +499,10 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, while(1) { int data1; - do_rom_fast_read(adapter, addridx, &data1); + ret = do_rom_fast_read(adapter, addridx, &data1); + if (ret < 0) + return ret; + if (data1 == data) break; @@ -753,7 +756,7 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) int n, i; int init_delay = 0; struct crb_addr_pair *buf; - unsigned long off; + u32 off; /* resetall */ status = netxen_nic_get_board_info(adapter); @@ -810,14 +813,13 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose) if (verbose) printk("%s: PCI: 0x%08x == 0x%08x\n", netxen_nic_driver_name, (unsigned int) - netxen_decode_crb_addr((unsigned long) - addr), val); + netxen_decode_crb_addr(addr), val); } for (i = 0; i < n; i++) { - off = netxen_decode_crb_addr((unsigned long)buf[i].addr); + off = netxen_decode_crb_addr(buf[i].addr); if (off == NETXEN_ADDR_ERROR) { - printk(KERN_ERR"CRB init value out of range %lx\n", + printk(KERN_ERR"CRB init value out of range %x\n", buf[i].addr); continue; } @@ -924,6 +926,10 @@ int netxen_initialize_adapter_offload(struct netxen_adapter *adapter) void netxen_free_adapter_offload(struct netxen_adapter *adapter) { if (adapter->dummy_dma.addr) { + writel(0, NETXEN_CRB_NORMALIZE(adapter, + CRB_HOST_DUMMY_BUF_ADDR_HI)); + writel(0, NETXEN_CRB_NORMALIZE(adapter, + CRB_HOST_DUMMY_BUF_ADDR_LO)); pci_free_consistent(adapter->ahw.pdev, NETXEN_HOST_DUMMY_DMA_SIZE, adapter->dummy_dma.addr, diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 225ff55527c..7d2525e76ab 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -42,8 +42,6 @@ #include <linux/dma-mapping.h> #include <linux/vmalloc.h> -#define PHAN_VENDOR_ID 0x4040 - MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID); @@ -379,6 +377,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->tx_timeout = netxen_tx_timeout; netdev->watchdog_timeo = HZ; + netxen_nic_change_mtu(netdev, netdev->mtu); + SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); netdev->poll = netxen_nic_poll; netdev->weight = NETXEN_NETDEV_WEIGHT; @@ -434,13 +434,11 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->port_count++; adapter->port[i] = port; } -#ifndef CONFIG_PPC64 writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); netxen_pinit_from_rom(adapter, 0); udelay(500); netxen_load_firmware(adapter); netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); -#endif /* * delay a while to ensure that the Pegs are up & running. * Otherwise, we might see some flaky behaviour. @@ -525,14 +523,17 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) if (adapter == NULL) return; + if (adapter->irq) + free_irq(adapter->irq, adapter); netxen_nic_stop_all_ports(adapter); /* leave the hw in the same state as reboot */ - netxen_pinit_from_rom(adapter, 0); writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); + netxen_pinit_from_rom(adapter, 0); + udelay(500); netxen_load_firmware(adapter); netxen_free_adapter_offload(adapter); - udelay(500); /* Delay for a while to drain the DMA engines */ + mdelay(1000); /* Delay for a while to drain the DMA engines */ for (i = 0; i < adapter->port_count; i++) { port = adapter->port[i]; if ((port) && (port->netdev)) { @@ -543,7 +544,6 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) if ((adapter->flags & NETXEN_NIC_MSI_ENABLED)) pci_disable_msi(pdev); - pci_set_drvdata(pdev, NULL); if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) netxen_free_hw_resources(adapter); @@ -554,6 +554,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) { recv_ctx = &adapter->recv_ctx[ctxid]; @@ -672,8 +673,6 @@ static int netxen_nic_close(struct net_device *netdev) if (!adapter->active_ports) { netxen_nic_disable_int(adapter); - if (adapter->irq) - free_irq(adapter->irq, adapter); cmd_buff = adapter->cmd_buf_arr; for (i = 0; i < adapter->max_tx_desc_count; i++) { buffrag = cmd_buff->frag_array; @@ -1155,8 +1154,8 @@ static void __exit netxen_exit_module(void) /* * Wait for some time to allow the dma to drain, if any. */ - destroy_workqueue(netxen_workq); pci_unregister_driver(&netxen_driver); + destroy_workqueue(netxen_workq); } module_exit(netxen_exit_module); diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index 7879f855af0..0c7c94328b7 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h @@ -102,6 +102,9 @@ #define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0) #define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4) +/* used for ethtool tests */ +#define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280) + /* * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address * which can be read by the Phantom host to get producer/consumer indexes from diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 196993a29b0..a6f4b24b017 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -104,8 +104,6 @@ static int automatic_resume; /* experimental .. better should be zero */ static int rfdadd; /* rfdadd=1 may be better for 8K MEM cards */ static int fifo=0x8; /* don't change */ -/* #define REALLY_SLOW_IO */ - #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 568daeb3e9d..9ec6e9e54f4 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -514,8 +514,7 @@ static void ns83820_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid spin_lock_irq(&dev->misc_lock); spin_lock(&dev->tx_lock); - if (dev->vlgrp) - dev->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(dev->vlgrp, vid, NULL); spin_unlock(&dev->tx_lock); spin_unlock_irq(&dev->misc_lock); } diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 36f9d988278..4d94ba7899b 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1234,14 +1234,14 @@ static void pcnet32_rx_entry(struct net_device *dev, skb_put(skb, pkt_len); /* Make room */ pci_dma_sync_single_for_cpu(lp->pci_dev, lp->rx_dma_addr[entry], - PKT_BUF_SZ - 2, + pkt_len, PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, (unsigned char *)(lp->rx_skbuff[entry]->data), pkt_len, 0); pci_dma_sync_single_for_device(lp->pci_dev, lp->rx_dma_addr[entry], - PKT_BUF_SZ - 2, + pkt_len, PCI_DMA_FROMDEVICE); } lp->stats.rx_bytes += skb->len; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 860bb0f60f6..ebfa2967cd6 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -7,6 +7,12 @@ * * Version: 0.7.0 * + * 070228 : Fix to allow multiple sessions with same remote MAC and same + * session id by including the local device ifindex in the + * tuple identifying a session. This also ensures packets can't + * be injected into a session from interfaces other than the one + * specified by userspace. Florian Zumbiehl <florz@florz.de> + * (Oh, BTW, this one is YYMMDD, in case you were wondering ...) * 220102 : Fix module use count on failure in pppoe_create, pppox_sk -acme * 030700 : Fixed connect logic to allow for disconnect. * 270700 : Fixed potential SMP problems; we must protect against @@ -127,14 +133,14 @@ static struct pppox_sock *item_hash_table[PPPOE_HASH_SIZE]; * Set/get/delete/rehash items (internal versions) * **********************************************************************/ -static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr) +static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr, int ifindex) { int hash = hash_item(sid, addr); struct pppox_sock *ret; ret = item_hash_table[hash]; - while (ret && !cmp_addr(&ret->pppoe_pa, sid, addr)) + while (ret && !(cmp_addr(&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex)) ret = ret->next; return ret; @@ -147,21 +153,19 @@ static int __set_item(struct pppox_sock *po) ret = item_hash_table[hash]; while (ret) { - if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa)) + if (cmp_2_addr(&ret->pppoe_pa, &po->pppoe_pa) && ret->pppoe_ifindex == po->pppoe_ifindex) return -EALREADY; ret = ret->next; } - if (!ret) { - po->next = item_hash_table[hash]; - item_hash_table[hash] = po; - } + po->next = item_hash_table[hash]; + item_hash_table[hash] = po; return 0; } -static struct pppox_sock *__delete_item(unsigned long sid, char *addr) +static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifindex) { int hash = hash_item(sid, addr); struct pppox_sock *ret, **src; @@ -170,7 +174,7 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr) src = &item_hash_table[hash]; while (ret) { - if (cmp_addr(&ret->pppoe_pa, sid, addr)) { + if (cmp_addr(&ret->pppoe_pa, sid, addr) && ret->pppoe_ifindex == ifindex) { *src = ret->next; break; } @@ -188,12 +192,12 @@ static struct pppox_sock *__delete_item(unsigned long sid, char *addr) * **********************************************************************/ static inline struct pppox_sock *get_item(unsigned long sid, - unsigned char *addr) + unsigned char *addr, int ifindex) { struct pppox_sock *po; read_lock_bh(&pppoe_hash_lock); - po = __get_item(sid, addr); + po = __get_item(sid, addr, ifindex); if (po) sock_hold(sk_pppox(po)); read_unlock_bh(&pppoe_hash_lock); @@ -203,7 +207,15 @@ static inline struct pppox_sock *get_item(unsigned long sid, static inline struct pppox_sock *get_item_by_addr(struct sockaddr_pppox *sp) { - return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote); + struct net_device *dev = NULL; + int ifindex; + + dev = dev_get_by_name(sp->sa_addr.pppoe.dev); + if(!dev) + return NULL; + ifindex = dev->ifindex; + dev_put(dev); + return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex); } static inline int set_item(struct pppox_sock *po) @@ -220,12 +232,12 @@ static inline int set_item(struct pppox_sock *po) return i; } -static inline struct pppox_sock *delete_item(unsigned long sid, char *addr) +static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex) { struct pppox_sock *ret; write_lock_bh(&pppoe_hash_lock); - ret = __delete_item(sid, addr); + ret = __delete_item(sid, addr, ifindex); write_unlock_bh(&pppoe_hash_lock); return ret; @@ -391,7 +403,7 @@ static int pppoe_rcv(struct sk_buff *skb, ph = (struct pppoe_hdr *) skb->nh.raw; - po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source); + po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); if (po != NULL) return sk_receive_skb(sk_pppox(po), skb, 0); drop: @@ -425,7 +437,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb, if (ph->code != PADT_CODE) goto abort; - po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source); + po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex); if (po) { struct sock *sk = sk_pppox(po); @@ -517,7 +529,7 @@ static int pppoe_release(struct socket *sock) po = pppox_sk(sk); if (po->pppoe_pa.sid) { - delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote); + delete_item(po->pppoe_pa.sid, po->pppoe_pa.remote, po->pppoe_ifindex); } if (po->pppoe_dev) @@ -539,7 +551,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, int sockaddr_len, int flags) { struct sock *sk = sock->sk; - struct net_device *dev = NULL; + struct net_device *dev; struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr; struct pppox_sock *po = pppox_sk(sk); int error; @@ -565,7 +577,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, pppox_unbind_sock(sk); /* Delete the old binding */ - delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote); + delete_item(po->pppoe_pa.sid,po->pppoe_pa.remote,po->pppoe_ifindex); if(po->pppoe_dev) dev_put(po->pppoe_dev); @@ -585,6 +597,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr, goto end; po->pppoe_dev = dev; + po->pppoe_ifindex = dev->ifindex; if (!(dev->flags & IFF_UP)) goto err_put; @@ -705,7 +718,7 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd, break; /* PPPoE address from the user specifies an outbound - PPPoE address to which frames are forwarded to */ + PPPoE address which frames are forwarded to */ err = -EFAULT; if (copy_from_user(&po->pppoe_relay, (void __user *)arg, diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index a142cdfd947..d3f65dab306 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -39,7 +39,7 @@ #define DRV_NAME "qla3xxx" #define DRV_STRING "QLogic ISP3XXX Network Driver" -#define DRV_VERSION "v2.02.00-k36" +#define DRV_VERSION "v2.03.00-k3" #define PFX DRV_NAME " " static const char ql3xxx_driver_name[] = DRV_NAME; @@ -276,7 +276,8 @@ static void ql_enable_interrupts(struct ql3_adapter *qdev) static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, struct ql_rcv_buf_cb *lrg_buf_cb) { - u64 map; + dma_addr_t map; + int err; lrg_buf_cb->next = NULL; if (qdev->lrg_buf_free_tail == NULL) { /* The list is empty */ @@ -287,9 +288,10 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, } if (!lrg_buf_cb->skb) { - lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len); + lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev, + qdev->lrg_buffer_len); if (unlikely(!lrg_buf_cb->skb)) { - printk(KERN_ERR PFX "%s: failed dev_alloc_skb().\n", + printk(KERN_ERR PFX "%s: failed netdev_alloc_skb().\n", qdev->ndev->name); qdev->lrg_buf_skb_check++; } else { @@ -303,6 +305,17 @@ static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev, qdev->lrg_buffer_len - QL_HEADER_SPACE, PCI_DMA_FROMDEVICE); + err = pci_dma_mapping_error(map); + if(err) { + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + qdev->ndev->name, err); + dev_kfree_skb(lrg_buf_cb->skb); + lrg_buf_cb->skb = NULL; + + qdev->lrg_buf_skb_check++; + return; + } + lrg_buf_cb->buf_phy_addr_low = cpu_to_le32(LS_64BITS(map)); lrg_buf_cb->buf_phy_addr_high = @@ -1387,6 +1400,8 @@ static void ql_link_state_machine(struct ql3_adapter *qdev) printk(KERN_INFO PFX "%s: Reset in progress, skip processing link " "state.\n", qdev->ndev->name); + + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); return; } @@ -1518,8 +1533,10 @@ static int ql_get_auto_cfg_status(struct ql3_adapter *qdev) spin_lock_irqsave(&qdev->hw_lock, hw_flags); if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * - 2) << 7)) + 2) << 7)) { + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); return 0; + } status = ql_is_auto_cfg(qdev); ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); @@ -1533,8 +1550,10 @@ static u32 ql_get_speed(struct ql3_adapter *qdev) spin_lock_irqsave(&qdev->hw_lock, hw_flags); if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * - 2) << 7)) + 2) << 7)) { + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); return 0; + } status = ql_get_link_speed(qdev); ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); @@ -1548,8 +1567,10 @@ static int ql_get_full_dup(struct ql3_adapter *qdev) spin_lock_irqsave(&qdev->hw_lock, hw_flags); if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * - 2) << 7)) + 2) << 7)) { + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); return 0; + } status = ql_is_link_full_dup(qdev); ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); @@ -1615,14 +1636,16 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = { static int ql_populate_free_queue(struct ql3_adapter *qdev) { struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head; - u64 map; + dma_addr_t map; + int err; while (lrg_buf_cb) { if (!lrg_buf_cb->skb) { - lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len); + lrg_buf_cb->skb = netdev_alloc_skb(qdev->ndev, + qdev->lrg_buffer_len); if (unlikely(!lrg_buf_cb->skb)) { printk(KERN_DEBUG PFX - "%s: Failed dev_alloc_skb().\n", + "%s: Failed netdev_alloc_skb().\n", qdev->ndev->name); break; } else { @@ -1636,6 +1659,17 @@ static int ql_populate_free_queue(struct ql3_adapter *qdev) qdev->lrg_buffer_len - QL_HEADER_SPACE, PCI_DMA_FROMDEVICE); + + err = pci_dma_mapping_error(map); + if(err) { + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + qdev->ndev->name, err); + dev_kfree_skb(lrg_buf_cb->skb); + lrg_buf_cb->skb = NULL; + break; + } + + lrg_buf_cb->buf_phy_addr_low = cpu_to_le32(LS_64BITS(map)); lrg_buf_cb->buf_phy_addr_high = @@ -1690,11 +1724,11 @@ static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev) qdev->lrg_buf_q_producer_index++; - if (qdev->lrg_buf_q_producer_index == NUM_LBUFQ_ENTRIES) + if (qdev->lrg_buf_q_producer_index == qdev->num_lbufq_entries) qdev->lrg_buf_q_producer_index = 0; if (qdev->lrg_buf_q_producer_index == - (NUM_LBUFQ_ENTRIES - 1)) { + (qdev->num_lbufq_entries - 1)) { lrg_buf_q_ele = qdev->lrg_buf_q_virt_addr; } } @@ -1713,8 +1747,31 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, { struct ql_tx_buf_cb *tx_cb; int i; + int retval = 0; + if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) { + printk(KERN_WARNING "Frame short but, frame was padded and sent.\n"); + } + tx_cb = &qdev->tx_buf[mac_rsp->transaction_id]; + + /* Check the transmit response flags for any errors */ + if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) { + printk(KERN_ERR "Frame too short to be legal, frame not sent.\n"); + + qdev->stats.tx_errors++; + retval = -EIO; + goto frame_not_sent; + } + + if(tx_cb->seg_count == 0) { + printk(KERN_ERR "tx_cb->seg_count == 0: %d\n", mac_rsp->transaction_id); + + qdev->stats.tx_errors++; + retval = -EIO; + goto invalid_seg_count; + } + pci_unmap_single(qdev->pdev, pci_unmap_addr(&tx_cb->map[0], mapaddr), pci_unmap_len(&tx_cb->map[0], maplen), @@ -1731,11 +1788,32 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, } qdev->stats.tx_packets++; qdev->stats.tx_bytes += tx_cb->skb->len; + +frame_not_sent: dev_kfree_skb_irq(tx_cb->skb); tx_cb->skb = NULL; + +invalid_seg_count: atomic_inc(&qdev->tx_count); } +void ql_get_sbuf(struct ql3_adapter *qdev) +{ + if (++qdev->small_buf_index == NUM_SMALL_BUFFERS) + qdev->small_buf_index = 0; + qdev->small_buf_release_cnt++; +} + +struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev) +{ + struct ql_rcv_buf_cb *lrg_buf_cb = NULL; + lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index]; + qdev->lrg_buf_release_cnt++; + if (++qdev->lrg_buf_index == qdev->num_large_buffers) + qdev->lrg_buf_index = 0; + return(lrg_buf_cb); +} + /* * The difference between 3022 and 3032 for inbound completions: * 3022 uses two buffers per completion. The first buffer contains @@ -1751,47 +1829,21 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev, static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, struct ib_mac_iocb_rsp *ib_mac_rsp_ptr) { - long int offset; - u32 lrg_buf_phy_addr_low = 0; struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL; struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL; - u32 *curr_ial_ptr; struct sk_buff *skb; u16 length = le16_to_cpu(ib_mac_rsp_ptr->length); /* * Get the inbound address list (small buffer). */ - offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE; - if (++qdev->small_buf_index == NUM_SMALL_BUFFERS) - qdev->small_buf_index = 0; + ql_get_sbuf(qdev); - curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset); - qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset; - qdev->small_buf_release_cnt++; - - if (qdev->device_id == QL3022_DEVICE_ID) { - /* start of first buffer (3022 only) */ - lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); - lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; - qdev->lrg_buf_release_cnt++; - if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) { - qdev->lrg_buf_index = 0; - } - curr_ial_ptr++; /* 64-bit pointers require two incs. */ - curr_ial_ptr++; - } + if (qdev->device_id == QL3022_DEVICE_ID) + lrg_buf_cb1 = ql_get_lbuf(qdev); /* start of second buffer */ - lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); - lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index]; - - /* - * Second buffer gets sent up the stack. - */ - qdev->lrg_buf_release_cnt++; - if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) - qdev->lrg_buf_index = 0; + lrg_buf_cb2 = ql_get_lbuf(qdev); skb = lrg_buf_cb2->skb; qdev->stats.rx_packets++; @@ -1819,11 +1871,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, struct ib_ip_iocb_rsp *ib_ip_rsp_ptr) { - long int offset; - u32 lrg_buf_phy_addr_low = 0; struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL; struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL; - u32 *curr_ial_ptr; struct sk_buff *skb1 = NULL, *skb2; struct net_device *ndev = qdev->ndev; u16 length = le16_to_cpu(ib_ip_rsp_ptr->length); @@ -1833,35 +1882,20 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, * Get the inbound address list (small buffer). */ - offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE; - if (++qdev->small_buf_index == NUM_SMALL_BUFFERS) - qdev->small_buf_index = 0; - curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset); - qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset; - qdev->small_buf_release_cnt++; + ql_get_sbuf(qdev); if (qdev->device_id == QL3022_DEVICE_ID) { /* start of first buffer on 3022 */ - lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); - lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index]; - qdev->lrg_buf_release_cnt++; - if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) - qdev->lrg_buf_index = 0; + lrg_buf_cb1 = ql_get_lbuf(qdev); skb1 = lrg_buf_cb1->skb; - curr_ial_ptr++; /* 64-bit pointers require two incs. */ - curr_ial_ptr++; size = ETH_HLEN; if (*((u16 *) skb1->data) != 0xFFFF) size += VLAN_ETH_HLEN - ETH_HLEN; } /* start of second buffer */ - lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr); - lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index]; + lrg_buf_cb2 = ql_get_lbuf(qdev); skb2 = lrg_buf_cb2->skb; - qdev->lrg_buf_release_cnt++; - if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) - qdev->lrg_buf_index = 0; skb_put(skb2, length); /* Just the second buffer length here. */ pci_unmap_single(qdev->pdev, @@ -1914,10 +1948,13 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev, struct net_rsp_iocb *net_rsp; struct net_device *ndev = qdev->ndev; unsigned long hw_flags; + int work_done = 0; + + u32 rsp_producer_index = le32_to_cpu(*(qdev->prsp_producer_index)); /* While there are entries in the completion queue. */ - while ((cpu_to_le32(*(qdev->prsp_producer_index)) != - qdev->rsp_consumer_index) && (*rx_cleaned < work_to_do)) { + while ((rsp_producer_index != + qdev->rsp_consumer_index) && (work_done < work_to_do)) { net_rsp = qdev->rsp_current; switch (net_rsp->opcode) { @@ -1968,37 +2005,34 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev, } else { qdev->rsp_current++; } + + work_done = *tx_cleaned + *rx_cleaned; } - spin_lock_irqsave(&qdev->hw_lock, hw_flags); + if(work_done) { + spin_lock_irqsave(&qdev->hw_lock, hw_flags); - ql_update_lrg_bufq_prod_index(qdev); + ql_update_lrg_bufq_prod_index(qdev); - if (qdev->small_buf_release_cnt >= 16) { - while (qdev->small_buf_release_cnt >= 16) { - qdev->small_buf_q_producer_index++; + if (qdev->small_buf_release_cnt >= 16) { + while (qdev->small_buf_release_cnt >= 16) { + qdev->small_buf_q_producer_index++; - if (qdev->small_buf_q_producer_index == - NUM_SBUFQ_ENTRIES) - qdev->small_buf_q_producer_index = 0; - qdev->small_buf_release_cnt -= 8; - } + if (qdev->small_buf_q_producer_index == + NUM_SBUFQ_ENTRIES) + qdev->small_buf_q_producer_index = 0; + qdev->small_buf_release_cnt -= 8; + } - ql_write_common_reg(qdev, - &port_regs->CommonRegs. - rxSmallQProducerIndex, - qdev->small_buf_q_producer_index); - } + wmb(); + ql_write_common_reg(qdev, + &port_regs->CommonRegs. + rxSmallQProducerIndex, + qdev->small_buf_q_producer_index); - ql_write_common_reg(qdev, - &port_regs->CommonRegs.rspQConsumerIndex, - qdev->rsp_consumer_index); - spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + } - if (unlikely(netif_queue_stopped(qdev->ndev))) { - if (netif_queue_stopped(qdev->ndev) && - (atomic_read(&qdev->tx_count) > (NUM_REQ_Q_ENTRIES / 4))) - netif_wake_queue(qdev->ndev); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); } return *tx_cleaned + *rx_cleaned; @@ -2009,6 +2043,8 @@ static int ql_poll(struct net_device *ndev, int *budget) struct ql3_adapter *qdev = netdev_priv(ndev); int work_to_do = min(*budget, ndev->quota); int rx_cleaned = 0, tx_cleaned = 0; + unsigned long hw_flags; + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; if (!netif_carrier_ok(ndev)) goto quit_polling; @@ -2017,9 +2053,17 @@ static int ql_poll(struct net_device *ndev, int *budget) *budget -= rx_cleaned; ndev->quota -= rx_cleaned; - if ((!tx_cleaned && !rx_cleaned) || !netif_running(ndev)) { + if( tx_cleaned + rx_cleaned != work_to_do || + !netif_running(ndev)) { quit_polling: netif_rx_complete(ndev); + + spin_lock_irqsave(&qdev->hw_lock, hw_flags); + ql_write_common_reg(qdev, + &port_regs->CommonRegs.rspQConsumerIndex, + qdev->rsp_consumer_index); + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + ql_enable_interrupts(qdev); return 0; } @@ -2073,10 +2117,9 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) spin_unlock(&qdev->adapter_lock); } else if (value & ISP_IMR_DISABLE_CMPL_INT) { ql_disable_interrupts(qdev); - if (likely(netif_rx_schedule_prep(ndev))) + if (likely(netif_rx_schedule_prep(ndev))) { __netif_rx_schedule(ndev); - else - ql_enable_interrupts(qdev); + } } else { return IRQ_NONE; } @@ -2093,8 +2136,12 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) * the next AOL if more frags are coming. * That is why the frags:segment count ratio is not linear. */ -static int ql_get_seg_count(unsigned short frags) +static int ql_get_seg_count(struct ql3_adapter *qdev, + unsigned short frags) { + if (qdev->device_id == QL3022_DEVICE_ID) + return 1; + switch(frags) { case 0: return 1; /* just the skb->data seg */ case 1: return 2; /* skb->data + 1 frag */ @@ -2139,11 +2186,13 @@ static void ql_hw_csum_setup(struct sk_buff *skb, if (ip) { if (ip->protocol == IPPROTO_TCP) { - mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC; + mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC | + OB_3032MAC_IOCB_REQ_IC; mac_iocb_ptr->ip_hdr_off = offset; mac_iocb_ptr->ip_hdr_len = ip->ihl; } else if (ip->protocol == IPPROTO_UDP) { - mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC; + mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC | + OB_3032MAC_IOCB_REQ_IC; mac_iocb_ptr->ip_hdr_off = offset; mac_iocb_ptr->ip_hdr_len = ip->ihl; } @@ -2151,53 +2200,42 @@ static void ql_hw_csum_setup(struct sk_buff *skb, } /* - * The difference between 3022 and 3032 sends: - * 3022 only supports a simple single segment transmission. - * 3032 supports checksumming and scatter/gather lists (fragments). - * The 3032 supports sglists by using the 3 addr/len pairs (ALP) - * in the IOCB plus a chain of outbound address lists (OAL) that - * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th) - * will used to point to an OAL when more ALP entries are required. - * The IOCB is always the top of the chain followed by one or more - * OALs (when necessary). + * Map the buffers for this transmit. This will return + * NETDEV_TX_BUSY or NETDEV_TX_OK based on success. */ -static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) +static int ql_send_map(struct ql3_adapter *qdev, + struct ob_mac_iocb_req *mac_iocb_ptr, + struct ql_tx_buf_cb *tx_cb, + struct sk_buff *skb) { - struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); - struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; - struct ql_tx_buf_cb *tx_cb; - u32 tot_len = skb->len; struct oal *oal; struct oal_entry *oal_entry; - int len; - struct ob_mac_iocb_req *mac_iocb_ptr; - u64 map; + int len = skb_headlen(skb); + dma_addr_t map; + int err; + int completed_segs, i; int seg_cnt, seg = 0; int frag_cnt = (int)skb_shinfo(skb)->nr_frags; - if (unlikely(atomic_read(&qdev->tx_count) < 2)) { - if (!netif_queue_stopped(ndev)) - netif_stop_queue(ndev); - return NETDEV_TX_BUSY; - } - tx_cb = &qdev->tx_buf[qdev->req_producer_index] ; - seg_cnt = tx_cb->seg_count = ql_get_seg_count((skb_shinfo(skb)->nr_frags)); + seg_cnt = tx_cb->seg_count = ql_get_seg_count(qdev, + (skb_shinfo(skb)->nr_frags)); if(seg_cnt == -1) { printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__); - return NETDEV_TX_OK; - + return NETDEV_TX_BUSY; } - mac_iocb_ptr = tx_cb->queue_entry; - memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req)); - mac_iocb_ptr->opcode = qdev->mac_ob_opcode; - mac_iocb_ptr->flags |= qdev->mb_bit_mask; - mac_iocb_ptr->transaction_id = qdev->req_producer_index; - mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len); - tx_cb->skb = skb; - if (skb->ip_summed == CHECKSUM_PARTIAL) - ql_hw_csum_setup(skb, mac_iocb_ptr); - len = skb_headlen(skb); + /* + * Map the skb buffer first. + */ map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE); + + err = pci_dma_mapping_error(map); + if(err) { + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + qdev->ndev->name, err); + + return NETDEV_TX_BUSY; + } + oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low; oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); @@ -2206,15 +2244,14 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) pci_unmap_len_set(&tx_cb->map[seg], maplen, len); seg++; - if (!skb_shinfo(skb)->nr_frags) { + if (seg_cnt == 1) { /* Terminate the last segment. */ oal_entry->len = cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY); } else { - int i; oal = tx_cb->oal; - for (i=0; i<frag_cnt; i++,seg++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + for (completed_segs=0; completed_segs<frag_cnt; completed_segs++,seg++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[completed_segs]; oal_entry++; if ((seg == 2 && seg_cnt > 3) || /* Check for continuation */ (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */ @@ -2224,6 +2261,15 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) map = pci_map_single(qdev->pdev, oal, sizeof(struct oal), PCI_DMA_TODEVICE); + + err = pci_dma_mapping_error(map); + if(err) { + + printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n", + qdev->ndev->name, err); + goto map_error; + } + oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); oal_entry->len = @@ -2242,6 +2288,14 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) pci_map_page(qdev->pdev, frag->page, frag->page_offset, frag->size, PCI_DMA_TODEVICE); + + err = pci_dma_mapping_error(map); + if(err) { + printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n", + qdev->ndev->name, err); + goto map_error; + } + oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map)); oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map)); oal_entry->len = cpu_to_le32(frag->size); @@ -2253,6 +2307,94 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) oal_entry->len = cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY); } + + return NETDEV_TX_OK; + +map_error: + /* A PCI mapping failed and now we will need to back out + * We need to traverse through the oal's and associated pages which + * have been mapped and now we must unmap them to clean up properly + */ + + seg = 1; + oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low; + oal = tx_cb->oal; + for (i=0; i<completed_segs; i++,seg++) { + oal_entry++; + + if((seg == 2 && seg_cnt > 3) || /* Check for continuation */ + (seg == 7 && seg_cnt > 8) || /* requirements. It's strange */ + (seg == 12 && seg_cnt > 13) || /* but necessary. */ + (seg == 17 && seg_cnt > 18)) { + pci_unmap_single(qdev->pdev, + pci_unmap_addr(&tx_cb->map[seg], mapaddr), + pci_unmap_len(&tx_cb->map[seg], maplen), + PCI_DMA_TODEVICE); + oal++; + seg++; + } + + pci_unmap_page(qdev->pdev, + pci_unmap_addr(&tx_cb->map[seg], mapaddr), + pci_unmap_len(&tx_cb->map[seg], maplen), + PCI_DMA_TODEVICE); + } + + pci_unmap_single(qdev->pdev, + pci_unmap_addr(&tx_cb->map[0], mapaddr), + pci_unmap_addr(&tx_cb->map[0], maplen), + PCI_DMA_TODEVICE); + + return NETDEV_TX_BUSY; + +} + +/* + * The difference between 3022 and 3032 sends: + * 3022 only supports a simple single segment transmission. + * 3032 supports checksumming and scatter/gather lists (fragments). + * The 3032 supports sglists by using the 3 addr/len pairs (ALP) + * in the IOCB plus a chain of outbound address lists (OAL) that + * each contain 5 ALPs. The last ALP of the IOCB (3rd) or OAL (5th) + * will used to point to an OAL when more ALP entries are required. + * The IOCB is always the top of the chain followed by one or more + * OALs (when necessary). + */ +static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev) +{ + struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); + struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; + struct ql_tx_buf_cb *tx_cb; + u32 tot_len = skb->len; + struct ob_mac_iocb_req *mac_iocb_ptr; + + if (unlikely(atomic_read(&qdev->tx_count) < 2)) { + return NETDEV_TX_BUSY; + } + + tx_cb = &qdev->tx_buf[qdev->req_producer_index] ; + if((tx_cb->seg_count = ql_get_seg_count(qdev, + (skb_shinfo(skb)->nr_frags))) == -1) { + printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__); + return NETDEV_TX_OK; + } + + mac_iocb_ptr = tx_cb->queue_entry; + mac_iocb_ptr->opcode = qdev->mac_ob_opcode; + mac_iocb_ptr->flags = OB_MAC_IOCB_REQ_X; + mac_iocb_ptr->flags |= qdev->mb_bit_mask; + mac_iocb_ptr->transaction_id = qdev->req_producer_index; + mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len); + tx_cb->skb = skb; + if (qdev->device_id == QL3032_DEVICE_ID && + skb->ip_summed == CHECKSUM_PARTIAL) + ql_hw_csum_setup(skb, mac_iocb_ptr); + + if(ql_send_map(qdev,mac_iocb_ptr,tx_cb,skb) != NETDEV_TX_OK) { + printk(KERN_ERR PFX"%s: Could not map the segments!\n",__func__); + return NETDEV_TX_BUSY; + } + wmb(); qdev->req_producer_index++; if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES) @@ -2338,12 +2480,19 @@ static int ql_alloc_buffer_queues(struct ql3_adapter *qdev) { /* Create Large Buffer Queue */ qdev->lrg_buf_q_size = - NUM_LBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry); + qdev->num_lbufq_entries * sizeof(struct lrg_buf_q_entry); if (qdev->lrg_buf_q_size < PAGE_SIZE) qdev->lrg_buf_q_alloc_size = PAGE_SIZE; else qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2; + qdev->lrg_buf = kmalloc(qdev->num_large_buffers * sizeof(struct ql_rcv_buf_cb),GFP_KERNEL); + if (qdev->lrg_buf == NULL) { + printk(KERN_ERR PFX + "%s: qdev->lrg_buf alloc failed.\n", qdev->ndev->name); + return -ENOMEM; + } + qdev->lrg_buf_q_alloc_virt_addr = pci_alloc_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size, @@ -2393,7 +2542,7 @@ static void ql_free_buffer_queues(struct ql3_adapter *qdev) "%s: Already done.\n", qdev->ndev->name); return; } - + if(qdev->lrg_buf) kfree(qdev->lrg_buf); pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size, qdev->lrg_buf_q_alloc_virt_addr, @@ -2438,8 +2587,6 @@ static int ql_alloc_small_buffers(struct ql3_adapter *qdev) small_buf_q_entry = qdev->small_buf_q_virt_addr; - qdev->last_rsp_offset = qdev->small_buf_phy_addr_low; - /* Initialize the small buffer queue. */ for (i = 0; i < (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES); i++) { small_buf_q_entry->addr_high = @@ -2476,7 +2623,7 @@ static void ql_free_large_buffers(struct ql3_adapter *qdev) int i = 0; struct ql_rcv_buf_cb *lrg_buf_cb; - for (i = 0; i < NUM_LARGE_BUFFERS; i++) { + for (i = 0; i < qdev->num_large_buffers; i++) { lrg_buf_cb = &qdev->lrg_buf[i]; if (lrg_buf_cb->skb) { dev_kfree_skb(lrg_buf_cb->skb); @@ -2497,7 +2644,7 @@ static void ql_init_large_buffers(struct ql3_adapter *qdev) struct ql_rcv_buf_cb *lrg_buf_cb; struct bufq_addr_element *buf_addr_ele = qdev->lrg_buf_q_virt_addr; - for (i = 0; i < NUM_LARGE_BUFFERS; i++) { + for (i = 0; i < qdev->num_large_buffers; i++) { lrg_buf_cb = &qdev->lrg_buf[i]; buf_addr_ele->addr_high = lrg_buf_cb->buf_phy_addr_high; buf_addr_ele->addr_low = lrg_buf_cb->buf_phy_addr_low; @@ -2512,10 +2659,12 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev) int i; struct ql_rcv_buf_cb *lrg_buf_cb; struct sk_buff *skb; - u64 map; + dma_addr_t map; + int err; - for (i = 0; i < NUM_LARGE_BUFFERS; i++) { - skb = dev_alloc_skb(qdev->lrg_buffer_len); + for (i = 0; i < qdev->num_large_buffers; i++) { + skb = netdev_alloc_skb(qdev->ndev, + qdev->lrg_buffer_len); if (unlikely(!skb)) { /* Better luck next round */ printk(KERN_ERR PFX @@ -2541,6 +2690,15 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev) qdev->lrg_buffer_len - QL_HEADER_SPACE, PCI_DMA_FROMDEVICE); + + err = pci_dma_mapping_error(map); + if(err) { + printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", + qdev->ndev->name, err); + ql_free_large_buffers(qdev); + return -ENOMEM; + } + pci_unmap_addr_set(lrg_buf_cb, mapaddr, map); pci_unmap_len_set(lrg_buf_cb, maplen, qdev->lrg_buffer_len - @@ -2592,9 +2750,15 @@ static int ql_create_send_free_list(struct ql3_adapter *qdev) static int ql_alloc_mem_resources(struct ql3_adapter *qdev) { - if (qdev->ndev->mtu == NORMAL_MTU_SIZE) + if (qdev->ndev->mtu == NORMAL_MTU_SIZE) { + qdev->num_lbufq_entries = NUM_LBUFQ_ENTRIES; qdev->lrg_buffer_len = NORMAL_MTU_SIZE; + } else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) { + /* + * Bigger buffers, so less of them. + */ + qdev->num_lbufq_entries = JUMBO_NUM_LBUFQ_ENTRIES; qdev->lrg_buffer_len = JUMBO_MTU_SIZE; } else { printk(KERN_ERR PFX @@ -2602,6 +2766,7 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev) qdev->ndev->name); return -ENOMEM; } + qdev->num_large_buffers = qdev->num_lbufq_entries * QL_ADDR_ELE_PER_BUFQ_ENTRY; qdev->lrg_buffer_len += VLAN_ETH_HLEN + VLAN_ID_LEN + QL_HEADER_SPACE; qdev->max_frame_size = (qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE; @@ -2834,7 +2999,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev) &hmem_regs->rxLargeQBaseAddrLow, LS_64BITS(qdev->lrg_buf_q_phy_addr)); - ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, NUM_LBUFQ_ENTRIES); + ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, qdev->num_lbufq_entries); ql_write_page1_reg(qdev, &hmem_regs->rxLargeBufferLength, @@ -2856,7 +3021,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev) qdev->small_buf_q_producer_index = NUM_SBUFQ_ENTRIES - 1; qdev->small_buf_release_cnt = 8; - qdev->lrg_buf_q_producer_index = NUM_LBUFQ_ENTRIES - 1; + qdev->lrg_buf_q_producer_index = qdev->num_lbufq_entries - 1; qdev->lrg_buf_release_cnt = 8; qdev->lrg_buf_next_free = (struct bufq_addr_element *)qdev->lrg_buf_q_virt_addr; @@ -3292,6 +3457,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev) err_init: ql_sem_unlock(qdev, QL_DRVR_SEM_MASK); err_lock: + spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); free_irq(qdev->pdev->irq, ndev); err_irq: if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) { @@ -3343,27 +3509,6 @@ static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev) return &qdev->stats; } -static int ql3xxx_change_mtu(struct net_device *ndev, int new_mtu) -{ - struct ql3_adapter *qdev = netdev_priv(ndev); - printk(KERN_ERR PFX "%s: new mtu size = %d.\n", ndev->name, new_mtu); - if (new_mtu != NORMAL_MTU_SIZE && new_mtu != JUMBO_MTU_SIZE) { - printk(KERN_ERR PFX - "%s: mtu size of %d is not valid. Use exactly %d or " - "%d.\n", ndev->name, new_mtu, NORMAL_MTU_SIZE, - JUMBO_MTU_SIZE); - return -EINVAL; - } - - if (!netif_running(ndev)) { - ndev->mtu = new_mtu; - return 0; - } - - ndev->mtu = new_mtu; - return ql_cycle_adapter(qdev,QL_DO_RESET); -} - static void ql3xxx_set_multicast_list(struct net_device *ndev) { /* @@ -3609,8 +3754,12 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, } ndev = alloc_etherdev(sizeof(struct ql3_adapter)); - if (!ndev) + if (!ndev) { + printk(KERN_ERR PFX "%s could not alloc etherdev\n", + pci_name(pdev)); + err = -ENOMEM; goto err_out_free_regions; + } SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, &pdev->dev); @@ -3639,6 +3788,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, if (!qdev->mem_map_registers) { printk(KERN_ERR PFX "%s: cannot map device registers\n", pci_name(pdev)); + err = -EIO; goto err_out_free_ndev; } @@ -3650,7 +3800,6 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, ndev->hard_start_xmit = ql3xxx_send; ndev->stop = ql3xxx_close; ndev->get_stats = ql3xxx_get_stats; - ndev->change_mtu = ql3xxx_change_mtu; ndev->set_multicast_list = ql3xxx_set_multicast_list; SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops); ndev->set_mac_address = ql3xxx_set_mac_address; @@ -3667,6 +3816,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, printk(KERN_ALERT PFX "ql3xxx_probe: Adapter #%d, Invalid NVRAM parameters.\n", qdev->index); + err = -EIO; goto err_out_iounmap; } @@ -3674,9 +3824,11 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, /* Validate and set parameters */ if (qdev->mac_index) { + ndev->mtu = qdev->nvram_data.macCfg_port1.etherMtu_mac ; memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn2.macAddress, ETH_ALEN); } else { + ndev->mtu = qdev->nvram_data.macCfg_port0.etherMtu_mac ; memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn0.macAddress, ETH_ALEN); } diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index b2d76ea6882..34cd6580fd0 100755 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h @@ -1014,13 +1014,15 @@ struct eeprom_data { /* Transmit and Receive Buffers */ #define NUM_LBUFQ_ENTRIES 128 +#define JUMBO_NUM_LBUFQ_ENTRIES \ +(NUM_LBUFQ_ENTRIES/(JUMBO_MTU_SIZE/NORMAL_MTU_SIZE)) #define NUM_SBUFQ_ENTRIES 64 #define QL_SMALL_BUFFER_SIZE 32 #define QL_ADDR_ELE_PER_BUFQ_ENTRY \ (sizeof(struct lrg_buf_q_entry) / sizeof(struct bufq_addr_element)) /* Each send has at least control block. This is how many we keep. */ #define NUM_SMALL_BUFFERS NUM_SBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY -#define NUM_LARGE_BUFFERS NUM_LBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY + #define QL_HEADER_SPACE 32 /* make header space at top of skb. */ /* * Large & Small Buffers for Receives @@ -1092,7 +1094,6 @@ struct oal_entry { u32 len; #define OAL_LAST_ENTRY 0x80000000 /* Last valid buffer in list. */ #define OAL_CONT_ENTRY 0x40000000 /* points to an OAL. (continuation) */ - u32 reserved; }; struct oal { @@ -1193,7 +1194,7 @@ struct ql3_adapter { struct net_rsp_iocb *rsp_current; u16 rsp_consumer_index; u16 reserved_06; - u32 *prsp_producer_index; + volatile u32 *prsp_producer_index; u32 rsp_producer_index_phy_addr_high; u32 rsp_producer_index_phy_addr_low; @@ -1207,9 +1208,11 @@ struct ql3_adapter { u32 lrg_buf_q_producer_index; u32 lrg_buf_release_cnt; struct bufq_addr_element *lrg_buf_next_free; + u32 num_large_buffers; + u32 num_lbufq_entries; /* Large (Receive) Buffers */ - struct ql_rcv_buf_cb lrg_buf[NUM_LARGE_BUFFERS]; + struct ql_rcv_buf_cb *lrg_buf; struct ql_rcv_buf_cb *lrg_buf_free_head; struct ql_rcv_buf_cb *lrg_buf_free_tail; u32 lrg_buf_free_count; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 13cf06ee97f..521b5f0618a 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -572,8 +572,8 @@ static void rtl8169_xmii_reset_enable(void __iomem *ioaddr) { unsigned int val; - mdio_write(ioaddr, MII_BMCR, BMCR_RESET); - val = mdio_read(ioaddr, MII_BMCR); + val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET; + mdio_write(ioaddr, MII_BMCR, val & 0xffff); } static void rtl8169_check_link_status(struct net_device *dev, @@ -890,8 +890,7 @@ static void rtl8169_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) unsigned long flags; spin_lock_irqsave(&tp->lock, flags); - if (tp->vlgrp) - tp->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(tp->vlgrp, vid, NULL); spin_unlock_irqrestore(&tp->lock, flags); } @@ -1369,11 +1368,7 @@ static inline void rtl8169_request_timer(struct net_device *dev) (tp->phy_version >= RTL_GIGA_PHY_VER_H)) return; - init_timer(timer); - timer->expires = jiffies + RTL8169_PHY_TIMEOUT; - timer->data = (unsigned long)(dev); - timer->function = rtl8169_phy_timer; - add_timer(timer); + mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT); } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1686,6 +1681,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->mmio_addr = ioaddr; tp->align = rtl_cfg_info[ent->driver_data].align; + init_timer(&tp->timer); + tp->timer.data = (unsigned long) dev; + tp->timer.function = rtl8169_phy_timer; + spin_lock_init(&tp->lock); rc = register_netdev(dev); diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 0e345cbc2bf..33fb7f3b704 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -430,6 +430,7 @@ struct XENA_dev_config { #define TX_PA_CFG_IGNORE_SNAP_OUI BIT(2) #define TX_PA_CFG_IGNORE_LLC_CTRL BIT(3) #define TX_PA_CFG_IGNORE_L2_ERR BIT(6) +#define RX_PA_CFG_STRIP_VLAN_TAG BIT(15) /* Recent add, used only debug purposes. */ u64 pcc_enable; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index fd85648d98d..46ebf141ee5 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -42,6 +42,14 @@ * Possible values '1' for enable '0' for disable. Default is '0' * lro_max_pkts: This parameter defines maximum number of packets can be * aggregated as a single large packet + * napi: This parameter used to enable/disable NAPI (polling Rx) + * Possible values '1' for enable and '0' for disable. Default is '1' + * ufo: This parameter used to enable/disable UDP Fragmentation Offload(UFO) + * Possible values '1' for enable and '0' for disable. Default is '0' + * vlan_tag_strip: This can be used to enable or disable vlan stripping. + * Possible values '1' for enable , '0' for disable. + * Default is '2' - which means disable in promisc mode + * and enable in non-promiscuous mode. ************************************************************************/ #include <linux/module.h> @@ -76,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.16.1" +#define DRV_VERSION "2.0.17.1" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -131,7 +139,7 @@ static char s2io_gstrings[][ETH_GSTRING_LEN] = { "BIST Test\t(offline)" }; -static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { +static char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = { {"tmac_frms"}, {"tmac_data_octets"}, {"tmac_drop_frms"}, @@ -225,7 +233,10 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"rxd_rd_cnt"}, {"rxd_wr_cnt"}, {"txf_rd_cnt"}, - {"rxf_wr_cnt"}, + {"rxf_wr_cnt"} +}; + +static char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = { {"rmac_ttl_1519_4095_frms"}, {"rmac_ttl_4096_8191_frms"}, {"rmac_ttl_8192_max_frms"}, @@ -241,7 +252,10 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"rmac_red_discard"}, {"rmac_rts_discard"}, {"rmac_ingm_full_discard"}, - {"link_fault_cnt"}, + {"link_fault_cnt"} +}; + +static char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { {"\n DRIVER STATISTICS"}, {"single_bit_ecc_errs"}, {"double_bit_ecc_errs"}, @@ -269,8 +283,16 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { ("lro_avg_aggr_pkts"), }; -#define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN -#define S2IO_STAT_STRINGS_LEN S2IO_STAT_LEN * ETH_GSTRING_LEN +#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN +#define S2IO_ENHANCED_STAT_LEN sizeof(ethtool_enhanced_stats_keys)/ \ + ETH_GSTRING_LEN +#define S2IO_DRIVER_STAT_LEN sizeof(ethtool_driver_stats_keys)/ ETH_GSTRING_LEN + +#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN ) +#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN ) + +#define XFRAME_I_STAT_STRINGS_LEN ( XFRAME_I_STAT_LEN * ETH_GSTRING_LEN ) +#define XFRAME_II_STAT_STRINGS_LEN ( XFRAME_II_STAT_LEN * ETH_GSTRING_LEN ) #define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN #define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN @@ -293,6 +315,9 @@ static void s2io_vlan_rx_register(struct net_device *dev, spin_unlock_irqrestore(&nic->tx_lock, flags); } +/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */ +int vlan_strip_flag; + /* Unregister the vlan */ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) { @@ -300,8 +325,7 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) unsigned long flags; spin_lock_irqsave(&nic->tx_lock, flags); - if (nic->vlgrp) - nic->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(nic->vlgrp, vid, NULL); spin_unlock_irqrestore(&nic->tx_lock, flags); } @@ -404,6 +428,7 @@ S2IO_PARM_INT(indicate_max_pkts, 0); S2IO_PARM_INT(napi, 1); S2IO_PARM_INT(ufo, 0); +S2IO_PARM_INT(vlan_tag_strip, NO_STRIP_IN_PROMISC); static unsigned int tx_fifo_len[MAX_TX_FIFOS] = {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; @@ -1371,6 +1396,16 @@ static int init_nic(struct s2io_nic *nic) &bar0->rts_frm_len_n[i]); } } + + /* Disable differentiated services steering logic */ + for (i = 0; i < 64; i++) { + if (rts_ds_steer(nic, i, 0) == FAILURE) { + DBG_PRINT(ERR_DBG, "%s: failed rts ds steering", + dev->name); + DBG_PRINT(ERR_DBG, "set on codepoint %d\n", i); + return FAILURE; + } + } /* Program statistics memory */ writeq(mac_control->stats_mem_phy, &bar0->stat_addr); @@ -1943,6 +1978,13 @@ static int start_nic(struct s2io_nic *nic) writeq(val64, &bar0->rx_pa_cfg); } + if (vlan_tag_strip == 0) { + val64 = readq(&bar0->rx_pa_cfg); + val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG; + writeq(val64, &bar0->rx_pa_cfg); + vlan_strip_flag = 0; + } + /* * Enabling MC-RLDRAM. After enabling the device, we timeout * for around 100ms, which is approximately the time required @@ -3195,26 +3237,37 @@ static void alarm_intr_handler(struct s2io_nic *nic) * SUCCESS on success and FAILURE on failure. */ -static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit) +static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit, + int bit_state) { - int ret = FAILURE, cnt = 0; + int ret = FAILURE, cnt = 0, delay = 1; u64 val64; - while (TRUE) { + if ((bit_state != S2IO_BIT_RESET) && (bit_state != S2IO_BIT_SET)) + return FAILURE; + + do { val64 = readq(addr); - if (!(val64 & busy_bit)) { - ret = SUCCESS; - break; + if (bit_state == S2IO_BIT_RESET) { + if (!(val64 & busy_bit)) { + ret = SUCCESS; + break; + } + } else { + if (!(val64 & busy_bit)) { + ret = SUCCESS; + break; + } } if(in_interrupt()) - mdelay(50); + mdelay(delay); else - msleep(50); + msleep(delay); - if (cnt++ > 10) - break; - } + if (++cnt >= 10) + delay = 50; + } while (cnt < 20); return ret; } /* @@ -3340,6 +3393,9 @@ new_way: writeq(val64, &bar0->pcc_err_reg); } + /* restore the previously assigned mac address */ + s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr); + sp->device_enabled_once = FALSE; } @@ -4087,6 +4143,11 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp) val64 &= ~GPIO_INT_MASK_LINK_UP; val64 |= GPIO_INT_MASK_LINK_DOWN; writeq(val64, &bar0->gpio_int_mask); + + /* turn off LED */ + val64 = readq(&bar0->adapter_control); + val64 = val64 &(~ADAPTER_LED_ON); + writeq(val64, &bar0->adapter_control); } } val64 = readq(&bar0->gpio_int_mask); @@ -4296,7 +4357,8 @@ static void s2io_set_multicast(struct net_device *dev) writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET); sp->m_cast_flg = 1; sp->all_multi_pos = MAC_MC_ALL_MC_ADDR_OFFSET; @@ -4312,7 +4374,8 @@ static void s2io_set_multicast(struct net_device *dev) writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET); sp->m_cast_flg = 0; sp->all_multi_pos = 0; @@ -4329,6 +4392,13 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); writel((u32) (val64 >> 32), (add + 4)); + if (vlan_tag_strip != 1) { + val64 = readq(&bar0->rx_pa_cfg); + val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG; + writeq(val64, &bar0->rx_pa_cfg); + vlan_strip_flag = 0; + } + val64 = readq(&bar0->mac_cfg); sp->promisc_flg = 1; DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n", @@ -4344,6 +4414,13 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); writel((u32) (val64 >> 32), (add + 4)); + if (vlan_tag_strip != 0) { + val64 = readq(&bar0->rx_pa_cfg); + val64 |= RX_PA_CFG_STRIP_VLAN_TAG; + writeq(val64, &bar0->rx_pa_cfg); + vlan_strip_flag = 1; + } + val64 = readq(&bar0->mac_cfg); sp->promisc_flg = 0; DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n", @@ -4378,7 +4455,8 @@ static void s2io_set_multicast(struct net_device *dev) /* Wait for command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) { + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); DBG_PRINT(ERR_DBG, "Multicasts failed\n"); @@ -4409,7 +4487,8 @@ static void s2io_set_multicast(struct net_device *dev) /* Wait for command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) { + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, + S2IO_BIT_RESET)) { DBG_PRINT(ERR_DBG, "%s: Adding ", dev->name); DBG_PRINT(ERR_DBG, "Multicasts failed\n"); @@ -4435,6 +4514,7 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) struct XENA_dev_config __iomem *bar0 = sp->bar0; register u64 val64, mac_addr = 0; int i; + u64 old_mac_addr = 0; /* * Set the new MAC address as the new unicast filter and reflect this @@ -4444,6 +4524,22 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) for (i = 0; i < ETH_ALEN; i++) { mac_addr <<= 8; mac_addr |= addr[i]; + old_mac_addr <<= 8; + old_mac_addr |= sp->def_mac_addr[0].mac_addr[i]; + } + + if(0 == mac_addr) + return SUCCESS; + + /* Update the internal structure with this new mac address */ + if(mac_addr != old_mac_addr) { + memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN)); + sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr); + sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8); + sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16); + sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24); + sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32); + sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40); } writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr), @@ -4455,7 +4551,7 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) writeq(val64, &bar0->rmac_addr_cmd_mem); /* Wait till command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING)) { + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) { DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name); return FAILURE; } @@ -4546,7 +4642,11 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, info->regdump_len = XENA_REG_SPACE; info->eedump_len = XENA_EEPROM_SPACE; info->testinfo_len = S2IO_TEST_LEN; - info->n_stats = S2IO_STAT_LEN; + + if (sp->device_type == XFRAME_I_DEVICE) + info->n_stats = XFRAME_I_STAT_LEN; + else + info->n_stats = XFRAME_II_STAT_LEN; } /** @@ -5568,22 +5668,30 @@ static void s2io_get_ethtool_stats(struct net_device *dev, tmp_stats[i++] = le32_to_cpu(stat_info->rxd_wr_cnt); tmp_stats[i++] = le32_to_cpu(stat_info->txf_rd_cnt); tmp_stats[i++] = le32_to_cpu(stat_info->rxf_wr_cnt); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_8192_max_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms); - tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard); - tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt); + + /* Enhanced statistics exist only for Hercules */ + if(sp->device_type == XFRAME_II_DEVICE) { + tmp_stats[i++] = + le64_to_cpu(stat_info->rmac_ttl_1519_4095_frms); + tmp_stats[i++] = + le64_to_cpu(stat_info->rmac_ttl_4096_8191_frms); + tmp_stats[i++] = + le64_to_cpu(stat_info->rmac_ttl_8192_max_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ttl_gt_max_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_osized_alt_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_jabber_alt_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_gt_max_alt_frms); + tmp_stats[i++] = le64_to_cpu(stat_info->rmac_vlan_frms); + tmp_stats[i++] = le32_to_cpu(stat_info->rmac_len_discard); + tmp_stats[i++] = le32_to_cpu(stat_info->rmac_fcs_discard); + tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pf_discard); + tmp_stats[i++] = le32_to_cpu(stat_info->rmac_da_discard); + tmp_stats[i++] = le32_to_cpu(stat_info->rmac_red_discard); + tmp_stats[i++] = le32_to_cpu(stat_info->rmac_rts_discard); + tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ingm_full_discard); + tmp_stats[i++] = le32_to_cpu(stat_info->link_fault_cnt); + } + tmp_stats[i++] = 0; tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs; tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs; @@ -5663,18 +5771,42 @@ static int s2io_ethtool_self_test_count(struct net_device *dev) static void s2io_ethtool_get_strings(struct net_device *dev, u32 stringset, u8 * data) { + int stat_size = 0; + struct s2io_nic *sp = dev->priv; + switch (stringset) { case ETH_SS_TEST: memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN); break; case ETH_SS_STATS: - memcpy(data, ðtool_stats_keys, - sizeof(ethtool_stats_keys)); + stat_size = sizeof(ethtool_xena_stats_keys); + memcpy(data, ðtool_xena_stats_keys,stat_size); + if(sp->device_type == XFRAME_II_DEVICE) { + memcpy(data + stat_size, + ðtool_enhanced_stats_keys, + sizeof(ethtool_enhanced_stats_keys)); + stat_size += sizeof(ethtool_enhanced_stats_keys); + } + + memcpy(data + stat_size, ðtool_driver_stats_keys, + sizeof(ethtool_driver_stats_keys)); } } static int s2io_ethtool_get_stats_count(struct net_device *dev) { - return (S2IO_STAT_LEN); + struct s2io_nic *sp = dev->priv; + int stat_count = 0; + switch(sp->device_type) { + case XFRAME_I_DEVICE: + stat_count = XFRAME_I_STAT_LEN; + break; + + case XFRAME_II_DEVICE: + stat_count = XFRAME_II_STAT_LEN; + break; + } + + return stat_count; } static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) @@ -5909,7 +6041,7 @@ static void s2io_set_link(struct work_struct *work) clear_bit(0, &(nic->link_state)); out_unlock: - rtnl_lock(); + rtnl_unlock(); } static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, @@ -6066,10 +6198,13 @@ static int rxd_owner_bit_reset(struct s2io_nic *sp) rx_blocks[j].rxds[k].virt_addr; if(sp->rxd_mode >= RXD_MODE_3A) ba = &mac_control->rings[i].ba[j][k]; - set_rxd_buffer_pointer(sp, rxdp, ba, + if (set_rxd_buffer_pointer(sp, rxdp, ba, &skb,(u64 *)&temp0_64, (u64 *)&temp1_64, - (u64 *)&temp2_64, size); + (u64 *)&temp2_64, + size) == ENOMEM) { + return 0; + } set_rxd_buffer_size(sp, rxdp, size); wmb(); @@ -6112,7 +6247,7 @@ static int s2io_add_isr(struct s2io_nic * sp) } } if (sp->intr_type == MSI_X) { - int i; + int i, msix_tx_cnt=0,msix_rx_cnt=0; for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) { if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) { @@ -6121,16 +6256,36 @@ static int s2io_add_isr(struct s2io_nic * sp) err = request_irq(sp->entries[i].vector, s2io_msix_fifo_handle, 0, sp->desc[i], sp->s2io_entries[i].arg); - DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i], - (unsigned long long)sp->msix_info[i].addr); + /* If either data or addr is zero print it */ + if(!(sp->msix_info[i].addr && + sp->msix_info[i].data)) { + DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx" + "Data:0x%lx\n",sp->desc[i], + (unsigned long long) + sp->msix_info[i].addr, + (unsigned long) + ntohl(sp->msix_info[i].data)); + } else { + msix_tx_cnt++; + } } else { sprintf(sp->desc[i], "%s:MSI-X-%d-RX", dev->name, i); err = request_irq(sp->entries[i].vector, s2io_msix_ring_handle, 0, sp->desc[i], sp->s2io_entries[i].arg); - DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i], - (unsigned long long)sp->msix_info[i].addr); + /* If either data or addr is zero print it */ + if(!(sp->msix_info[i].addr && + sp->msix_info[i].data)) { + DBG_PRINT(ERR_DBG, "%s @ Addr:0x%llx" + "Data:0x%lx\n",sp->desc[i], + (unsigned long long) + sp->msix_info[i].addr, + (unsigned long) + ntohl(sp->msix_info[i].data)); + } else { + msix_rx_cnt++; + } } if (err) { DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration " @@ -6140,6 +6295,8 @@ static int s2io_add_isr(struct s2io_nic * sp) } sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS; } + printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt); + printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt); } if (sp->intr_type == INTA) { err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED, @@ -6567,7 +6724,8 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) if (!sp->lro) { skb->protocol = eth_type_trans(skb, dev); - if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { + if ((sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2) && + vlan_strip_flag)) { /* Queueing the vlan frame to the upper layer */ if (napi) vlan_hwaccel_receive_skb(skb, sp->vlgrp, @@ -6704,8 +6862,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) "Defaulting to INTA\n"); *dev_intr_type = INTA; } - if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) ) - napi = 0; + if (rx_ring_mode > 3) { DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n"); DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n"); @@ -6715,6 +6872,37 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type) } /** + * rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS + * or Traffic class respectively. + * @nic: device peivate variable + * Description: The function configures the receive steering to + * desired receive ring. + * Return Value: SUCCESS on success and + * '-1' on failure (endian settings incorrect). + */ +static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring) +{ + struct XENA_dev_config __iomem *bar0 = nic->bar0; + register u64 val64 = 0; + + if (ds_codepoint > 63) + return FAILURE; + + val64 = RTS_DS_MEM_DATA(ring); + writeq(val64, &bar0->rts_ds_mem_data); + + val64 = RTS_DS_MEM_CTRL_WE | + RTS_DS_MEM_CTRL_STROBE_NEW_CMD | + RTS_DS_MEM_CTRL_OFFSET(ds_codepoint); + + writeq(val64, &bar0->rts_ds_mem_ctrl); + + return wait_for_cmd_complete(&bar0->rts_ds_mem_ctrl, + RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED, + S2IO_BIT_RESET); +} + +/** * 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. @@ -7008,13 +7196,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) RMAC_ADDR_CMD_MEM_OFFSET(0 + MAC_MAC_ADDR_START_OFFSET); writeq(val64, &bar0->rmac_addr_cmd_mem); wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, - RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING); + RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET); tmp64 = readq(&bar0->rmac_addr_data0_mem); mac_down = (u32) tmp64; mac_up = (u32) (tmp64 >> 32); - memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN)); - sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up); sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8); sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 0de0c65f945..803137ca4b6 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -32,7 +32,8 @@ #define FAILURE -1 #define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL #define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100 - +#define S2IO_BIT_RESET 1 +#define S2IO_BIT_SET 2 #define CHECKBIT(value, nbit) (value & (1 << nbit)) /* Maximum time to flicker LED when asked to identify NIC using ethtool */ @@ -296,6 +297,9 @@ struct stat_block { struct xpakStat xpak_stat; }; +/* Default value for 'vlan_strip_tag' configuration parameter */ +#define NO_STRIP_IN_PROMISC 2 + /* * Structures representing different init time configuration * parameters of the NIC. @@ -1005,7 +1009,8 @@ static int s2io_set_swapper(struct s2io_nic * sp); static void s2io_card_down(struct s2io_nic *nic); static int s2io_card_up(struct s2io_nic *nic); static int get_xena_rev_id(struct pci_dev *pdev); -static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit); +static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit, + int bit_state); static int s2io_add_isr(struct s2io_nic * sp); static void s2io_rem_isr(struct s2io_nic * sp); @@ -1019,6 +1024,7 @@ static void queue_rx_frame(struct sk_buff *skb); static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro); static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, struct sk_buff *skb, u32 tcp_len); +static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring); #define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size #define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index a833e7f9757..52ed522a234 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -12,26 +12,15 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/socket.h> -#include <linux/in.h> -#include <linux/route.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <linux/bitops.h> -#include <asm/byteorder.h> -#include <asm/io.h> -#include <asm/system.h> -#include <asm/page.h> -#include <asm/pgtable.h> #include <asm/sgi/hpc3.h> #include <asm/sgi/ip22.h> -#include <asm/sgialib.h> #include "sgiseeq.h" diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index fb2b5305163..b3750f28427 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -968,10 +968,10 @@ static void mdio_write(struct net_device *net_dev, int phy_id, int location, static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr) { - int i = 0; + int i; u16 status; - while (i++ < 2) + for (i = 0; i < 2; i++) status = mdio_read(net_dev, phy_addr, MII_STATUS); mdio_write( net_dev, phy_addr, MII_CONTROL, MII_CNTL_RESET ); @@ -1430,7 +1430,7 @@ static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr) int i = 0; u32 status; - while (i++ < 2) + for (i = 0; i < 2; i++) status = mdio_read(net_dev, phy_addr, MII_STATUS); if (!(status & MII_STAT_LINK)){ @@ -1466,9 +1466,9 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex int phy_addr = sis_priv->cur_phy; u32 status; u16 autoadv, autorec; - int i = 0; + int i; - while (i++ < 2) + for (i = 0; i < 2; i++) status = mdio_read(net_dev, phy_addr, MII_STATUS); if (!(status & MII_STAT_LINK)) diff --git a/drivers/net/skfp/cfm.c b/drivers/net/skfp/cfm.c index 4c8aaa76233..5310d39b573 100644 --- a/drivers/net/skfp/cfm.c +++ b/drivers/net/skfp/cfm.c @@ -73,7 +73,7 @@ static const char * const cfm_events[] = { /* * map from state to downstream port type */ -static const u_char cf_to_ptype[] = { +static const unsigned char cf_to_ptype[] = { TNONE,TNONE,TNONE,TNONE,TNONE, TNONE,TB,TB,TS, TA,TB,TS,TB diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c3d2e0a2c4e..eea75a401b0 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -77,13 +77,13 @@ static const struct pci_device_id skge_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), }, + { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T) }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b01) }, /* DGE-530T */ { 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_EG1064) }, - { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015 }, { 0 } }; MODULE_DEVICE_TABLE(pci, skge_id_table); @@ -2767,6 +2767,17 @@ static int skge_change_mtu(struct net_device *dev, int new_mtu) return err; } +static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 }; + +static void genesis_add_filter(u8 filter[8], const u8 *addr) +{ + u32 crc, bit; + + crc = ether_crc_le(ETH_ALEN, addr); + bit = ~crc & 0x3f; + filter[bit/8] |= 1 << (bit%8); +} + static void genesis_set_multicast(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); @@ -2788,24 +2799,33 @@ static void genesis_set_multicast(struct net_device *dev) memset(filter, 0xff, sizeof(filter)); else { memset(filter, 0, sizeof(filter)); - for (i = 0; list && i < count; i++, list = list->next) { - u32 crc, bit; - crc = ether_crc_le(ETH_ALEN, list->dmi_addr); - bit = ~crc & 0x3f; - filter[bit/8] |= 1 << (bit%8); - } + + if (skge->flow_status == FLOW_STAT_REM_SEND + || skge->flow_status == FLOW_STAT_SYMMETRIC) + genesis_add_filter(filter, pause_mc_addr); + + for (i = 0; list && i < count; i++, list = list->next) + genesis_add_filter(filter, list->dmi_addr); } xm_write32(hw, port, XM_MODE, mode); xm_outhash(hw, port, XM_HSM, filter); } +static void yukon_add_filter(u8 filter[8], const u8 *addr) +{ + u32 bit = ether_crc(ETH_ALEN, addr) & 0x3f; + filter[bit/8] |= 1 << (bit%8); +} + static void yukon_set_multicast(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; int port = skge->port; struct dev_mc_list *list = dev->mc_list; + int rx_pause = (skge->flow_status == FLOW_STAT_REM_SEND + || skge->flow_status == FLOW_STAT_SYMMETRIC); u16 reg; u8 filter[8]; @@ -2818,16 +2838,17 @@ static void yukon_set_multicast(struct net_device *dev) reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); else if (dev->flags & IFF_ALLMULTI) /* all multicast */ memset(filter, 0xff, sizeof(filter)); - else if (dev->mc_count == 0) /* no multicast */ + else if (dev->mc_count == 0 && !rx_pause)/* no multicast */ reg &= ~GM_RXCR_MCF_ENA; else { int i; reg |= GM_RXCR_MCF_ENA; - for (i = 0; list && i < dev->mc_count; i++, list = list->next) { - u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f; - filter[bit/8] |= 1 << (bit%8); - } + if (rx_pause) + yukon_add_filter(filter, pause_mc_addr); + + for (i = 0; list && i < dev->mc_count; i++, list = list->next) + yukon_add_filter(filter, list->dmi_addr); } diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 17b1b479dff..e9354dfa7e9 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -1849,8 +1849,7 @@ enum { GMR_FS_JABBER, /* Rx GMAC FIFO Flush Mask (default) */ RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR | - GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE | - GMR_FS_JABBER, + GMR_FS_BAD_FC | GMR_FS_UN_SIZE | GMR_FS_JABBER, }; /* RX_GMF_CTRL_T 32 bit Rx GMAC FIFO Control/Test */ diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 52edbd7ac17..ab0ab92583f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1053,8 +1053,7 @@ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF); sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF); - if (sky2->vlgrp) - sky2->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(sky2->vlgrp, vid, NULL); netif_tx_unlock_bh(dev); } @@ -2166,9 +2165,27 @@ force_update: /* fall through */ #endif case OP_RXCHKS: - skb = sky2->rx_ring[sky2->rx_next].skb; - skb->ip_summed = CHECKSUM_COMPLETE; - skb->csum = status & 0xffff; + if (!sky2->rx_csum) + break; + + /* Both checksum counters are programmed to start at + * the same offset, so unless there is a problem they + * should match. This failure is an early indication that + * hardware receive checksumming won't work. + */ + if (likely(status >> 16 == (status & 0xffff))) { + skb = sky2->rx_ring[sky2->rx_next].skb; + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = status & 0xffff; + } else { + printk(KERN_NOTICE PFX "%s: hardware receive " + "checksum problem (status = %#x)\n", + dev->name, status); + sky2->rx_csum = 0; + sky2_write32(sky2->hw, + Q_ADDR(rxqaddr[le->link], Q_CSR), + BMU_DIS_RX_CHKSUM); + } break; case OP_TXINDEXLE: diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 64ed8ff5b03..3b91af89e4c 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1,7 +1,8 @@ /* - * Network device driver for Cell Processor-Based Blade + * Network device driver for Cell Processor-Based Blade and Celleb platform * * (C) Copyright IBM Corp. 2005 + * (C) Copyright 2006 TOSHIBA CORPORATION * * Authors : Utz Bacher <utz.bacher@de.ibm.com> * Jens Osterkamp <Jens.Osterkamp@de.ibm.com> @@ -166,6 +167,41 @@ spider_net_read_phy(struct net_device *netdev, int mii_id, int reg) } /** + * spider_net_setup_aneg - initial auto-negotiation setup + * @card: device structure + **/ +static void +spider_net_setup_aneg(struct spider_net_card *card) +{ + struct mii_phy *phy = &card->phy; + u32 advertise = 0; + u16 bmcr, bmsr, stat1000, estat; + + bmcr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMCR); + bmsr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR); + stat1000 = spider_net_read_phy(card->netdev, phy->mii_id, MII_STAT1000); + estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS); + + if (bmsr & BMSR_10HALF) + advertise |= ADVERTISED_10baseT_Half; + if (bmsr & BMSR_10FULL) + advertise |= ADVERTISED_10baseT_Full; + if (bmsr & BMSR_100HALF) + advertise |= ADVERTISED_100baseT_Half; + if (bmsr & BMSR_100FULL) + advertise |= ADVERTISED_100baseT_Full; + + if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL)) + advertise |= SUPPORTED_1000baseT_Full; + if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF)) + advertise |= SUPPORTED_1000baseT_Half; + + mii_phy_probe(phy, phy->mii_id); + phy->def->ops->setup_aneg(phy, advertise); + +} + +/** * spider_net_rx_irq_off - switch off rx irq on this spider card * @card: device structure * @@ -263,9 +299,9 @@ spider_net_get_mac_address(struct net_device *netdev) * returns the status as in the dmac_cmd_status field of the descriptor */ static inline int -spider_net_get_descr_status(struct spider_net_descr *descr) +spider_net_get_descr_status(struct spider_net_hw_descr *hwdescr) { - return descr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK; + return hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK; } /** @@ -283,12 +319,12 @@ spider_net_free_chain(struct spider_net_card *card, descr = chain->ring; do { descr->bus_addr = 0; - descr->next_descr_addr = 0; + descr->hwdescr->next_descr_addr = 0; descr = descr->next; } while (descr != chain->ring); dma_free_coherent(&card->pdev->dev, chain->num_desc, - chain->ring, chain->dma_addr); + chain->hwring, chain->dma_addr); } /** @@ -307,31 +343,34 @@ spider_net_init_chain(struct spider_net_card *card, { int i; struct spider_net_descr *descr; + struct spider_net_hw_descr *hwdescr; dma_addr_t buf; size_t alloc_size; - alloc_size = chain->num_desc * sizeof (struct spider_net_descr); + alloc_size = chain->num_desc * sizeof(struct spider_net_hw_descr); - chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size, + chain->hwring = dma_alloc_coherent(&card->pdev->dev, alloc_size, &chain->dma_addr, GFP_KERNEL); - if (!chain->ring) + if (!chain->hwring) return -ENOMEM; - descr = chain->ring; - memset(descr, 0, alloc_size); + memset(chain->ring, 0, chain->num_desc * sizeof(struct spider_net_descr)); /* Set up the hardware pointers in each descriptor */ + descr = chain->ring; + hwdescr = chain->hwring; buf = chain->dma_addr; - for (i=0; i < chain->num_desc; i++, descr++) { - descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + for (i=0; i < chain->num_desc; i++, descr++, hwdescr++) { + hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + hwdescr->next_descr_addr = 0; + descr->hwdescr = hwdescr; descr->bus_addr = buf; - descr->next_descr_addr = 0; descr->next = descr + 1; descr->prev = descr - 1; - buf += sizeof(struct spider_net_descr); + buf += sizeof(struct spider_net_hw_descr); } /* do actual circular list */ (descr-1)->next = chain->ring; @@ -357,10 +396,11 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) descr = card->rx_chain.head; do { if (descr->skb) { - dev_kfree_skb(descr->skb); - pci_unmap_single(card->pdev, descr->buf_addr, + pci_unmap_single(card->pdev, descr->hwdescr->buf_addr, SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL); + dev_kfree_skb(descr->skb); + descr->skb = NULL; } descr = descr->next; } while (descr != card->rx_chain.head); @@ -380,6 +420,7 @@ static int spider_net_prepare_rx_descr(struct spider_net_card *card, struct spider_net_descr *descr) { + struct spider_net_hw_descr *hwdescr = descr->hwdescr; dma_addr_t buf; int offset; int bufsize; @@ -398,11 +439,11 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, card->spider_stats.alloc_rx_skb_error++; return -ENOMEM; } - descr->buf_size = bufsize; - descr->result_size = 0; - descr->valid_size = 0; - descr->data_status = 0; - descr->data_error = 0; + hwdescr->buf_size = bufsize; + hwdescr->result_size = 0; + hwdescr->valid_size = 0; + hwdescr->data_status = 0; + hwdescr->data_error = 0; offset = ((unsigned long)descr->skb->data) & (SPIDER_NET_RXBUF_ALIGN - 1); @@ -411,21 +452,22 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, /* iommu-map the skb */ buf = pci_map_single(card->pdev, descr->skb->data, SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); - descr->buf_addr = buf; if (pci_dma_mapping_error(buf)) { dev_kfree_skb_any(descr->skb); + descr->skb = NULL; if (netif_msg_rx_err(card) && net_ratelimit()) pr_err("Could not iommu-map rx buffer\n"); card->spider_stats.rx_iommu_map_error++; - descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; } else { - descr->next_descr_addr = 0; + hwdescr->buf_addr = buf; + hwdescr->next_descr_addr = 0; wmb(); - descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | + hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOINTR_COMPLETE; wmb(); - descr->prev->next_descr_addr = descr->bus_addr; + descr->prev->hwdescr->next_descr_addr = descr->bus_addr; } return 0; @@ -481,7 +523,7 @@ spider_net_refill_rx_chain(struct spider_net_card *card) if (!spin_trylock_irqsave(&chain->lock, flags)) return; - while (spider_net_get_descr_status(chain->head) == + while (spider_net_get_descr_status(chain->head->hwdescr) == SPIDER_NET_DESCR_NOT_IN_USE) { if (spider_net_prepare_rx_descr(card, chain->head)) break; @@ -642,7 +684,9 @@ static int spider_net_prepare_tx_descr(struct spider_net_card *card, struct sk_buff *skb) { + struct spider_net_descr_chain *chain = &card->tx_chain; struct spider_net_descr *descr; + struct spider_net_hw_descr *hwdescr; dma_addr_t buf; unsigned long flags; @@ -655,32 +699,39 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, return -ENOMEM; } - spin_lock_irqsave(&card->tx_chain.lock, flags); + spin_lock_irqsave(&chain->lock, flags); descr = card->tx_chain.head; - card->tx_chain.head = descr->next; + if (descr->next == chain->tail->prev) { + spin_unlock_irqrestore(&chain->lock, flags); + pci_unmap_single(card->pdev, buf, skb->len, PCI_DMA_TODEVICE); + return -ENOMEM; + } + hwdescr = descr->hwdescr; + chain->head = descr->next; - descr->buf_addr = buf; - descr->buf_size = skb->len; - descr->next_descr_addr = 0; descr->skb = skb; - descr->data_status = 0; + hwdescr->buf_addr = buf; + hwdescr->buf_size = skb->len; + hwdescr->next_descr_addr = 0; + hwdescr->data_status = 0; - descr->dmac_cmd_status = + hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS; - spin_unlock_irqrestore(&card->tx_chain.lock, flags); + spin_unlock_irqrestore(&chain->lock, flags); if (skb->protocol == htons(ETH_P_IP)) switch (skb->nh.iph->protocol) { case IPPROTO_TCP: - descr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP; + hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP; break; case IPPROTO_UDP: - descr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP; + hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP; break; } /* Chain the bus address, so that the DMA engine finds this descr. */ - descr->prev->next_descr_addr = descr->bus_addr; + wmb(); + descr->prev->hwdescr->next_descr_addr = descr->bus_addr; card->netdev->trans_start = jiffies; /* set netdev watchdog timer */ return 0; @@ -689,16 +740,17 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, static int spider_net_set_low_watermark(struct spider_net_card *card) { + struct spider_net_descr *descr = card->tx_chain.tail; + struct spider_net_hw_descr *hwdescr; unsigned long flags; int status; int cnt=0; int i; - struct spider_net_descr *descr = card->tx_chain.tail; /* Measure the length of the queue. Measurement does not * need to be precise -- does not need a lock. */ while (descr != card->tx_chain.head) { - status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE; + status = descr->hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE; if (status == SPIDER_NET_DESCR_NOT_IN_USE) break; descr = descr->next; @@ -717,10 +769,12 @@ spider_net_set_low_watermark(struct spider_net_card *card) /* Set the new watermark, clear the old watermark */ spin_lock_irqsave(&card->tx_chain.lock, flags); - descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG; - if (card->low_watermark && card->low_watermark != descr) - card->low_watermark->dmac_cmd_status = - card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; + descr->hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG; + if (card->low_watermark && card->low_watermark != descr) { + hwdescr = card->low_watermark->hwdescr; + hwdescr->dmac_cmd_status = + hwdescr->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; + } card->low_watermark = descr; spin_unlock_irqrestore(&card->tx_chain.lock, flags); return cnt; @@ -743,16 +797,22 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) { struct spider_net_descr_chain *chain = &card->tx_chain; struct spider_net_descr *descr; + struct spider_net_hw_descr *hwdescr; struct sk_buff *skb; u32 buf_addr; unsigned long flags; int status; - while (chain->tail != chain->head) { + while (1) { spin_lock_irqsave(&chain->lock, flags); + if (chain->tail == chain->head) { + spin_unlock_irqrestore(&chain->lock, flags); + return 0; + } descr = chain->tail; + hwdescr = descr->hwdescr; - status = spider_net_get_descr_status(descr); + status = spider_net_get_descr_status(hwdescr); switch (status) { case SPIDER_NET_DESCR_COMPLETE: card->netdev_stats.tx_packets++; @@ -788,9 +848,10 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) } chain->tail = descr->next; - descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; + hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; skb = descr->skb; - buf_addr = descr->buf_addr; + descr->skb = NULL; + buf_addr = hwdescr->buf_addr; spin_unlock_irqrestore(&chain->lock, flags); /* unmap the skb */ @@ -826,7 +887,7 @@ spider_net_kick_tx_dma(struct spider_net_card *card) descr = card->tx_chain.tail; for (;;) { - if (spider_net_get_descr_status(descr) == + if (spider_net_get_descr_status(descr->hwdescr) == SPIDER_NET_DESCR_CARDOWNED) { spider_net_write_reg(card, SPIDER_NET_GDTDCHA, descr->bus_addr); @@ -855,13 +916,10 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) { int cnt; struct spider_net_card *card = netdev_priv(netdev); - struct spider_net_descr_chain *chain = &card->tx_chain; spider_net_release_tx_chain(card, 0); - if ((chain->head->next == chain->tail->prev) || - (spider_net_prepare_tx_descr(card, skb) != 0)) { - + if (spider_net_prepare_tx_descr(card, skb) != 0) { card->netdev_stats.tx_dropped++; netif_stop_queue(netdev); return NETDEV_TX_BUSY; @@ -922,17 +980,18 @@ static void spider_net_pass_skb_up(struct spider_net_descr *descr, struct spider_net_card *card) { + struct spider_net_hw_descr *hwdescr= descr->hwdescr; struct sk_buff *skb; struct net_device *netdev; u32 data_status, data_error; - data_status = descr->data_status; - data_error = descr->data_error; + data_status = hwdescr->data_status; + data_error = hwdescr->data_error; netdev = card->netdev; skb = descr->skb; skb->dev = netdev; - skb_put(skb, descr->valid_size); + skb_put(skb, hwdescr->valid_size); /* the card seems to add 2 bytes of junk in front * of the ethernet frame */ @@ -994,23 +1053,25 @@ static void show_rx_chain(struct spider_net_card *card) #endif /** - * spider_net_decode_one_descr - processes an rx descriptor + * spider_net_decode_one_descr - processes an RX descriptor * @card: card structure * - * Returns 1 if a packet has been sent to the stack, otherwise 0 + * Returns 1 if a packet has been sent to the stack, otherwise 0. * - * Processes an rx descriptor by iommu-unmapping the data buffer and passing - * the packet up to the stack. This function is called in softirq - * context, e.g. either bottom half from interrupt or NAPI polling context + * Processes an RX descriptor by iommu-unmapping the data buffer + * and passing the packet up to the stack. This function is called + * in softirq context, e.g. either bottom half from interrupt or + * NAPI polling context. */ static int spider_net_decode_one_descr(struct spider_net_card *card) { struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *descr = chain->tail; + struct spider_net_hw_descr *hwdescr = descr->hwdescr; int status; - status = spider_net_get_descr_status(descr); + status = spider_net_get_descr_status(hwdescr); /* Nothing in the descriptor, or ring must be empty */ if ((status == SPIDER_NET_DESCR_CARDOWNED) || @@ -1021,7 +1082,7 @@ spider_net_decode_one_descr(struct spider_net_card *card) chain->tail = descr->next; /* unmap descriptor */ - pci_unmap_single(card->pdev, descr->buf_addr, + pci_unmap_single(card->pdev, hwdescr->buf_addr, SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) || @@ -1037,34 +1098,33 @@ spider_net_decode_one_descr(struct spider_net_card *card) if ( (status != SPIDER_NET_DESCR_COMPLETE) && (status != SPIDER_NET_DESCR_FRAME_END) ) { if (netif_msg_rx_err(card)) - pr_err("%s: RX descriptor with unkown state %d\n", + pr_err("%s: RX descriptor with unknown state %d\n", card->netdev->name, status); card->spider_stats.rx_desc_unk_state++; goto bad_desc; } /* The cases we'll throw away the packet immediately */ - if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) { + if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) { if (netif_msg_rx_err(card)) pr_err("%s: error in received descriptor found, " "data_status=x%08x, data_error=x%08x\n", card->netdev->name, - descr->data_status, descr->data_error); + hwdescr->data_status, hwdescr->data_error); goto bad_desc; } - if (descr->dmac_cmd_status & 0xfefe) { + if (hwdescr->dmac_cmd_status & 0xfefe) { pr_err("%s: bad status, cmd_status=x%08x\n", card->netdev->name, - descr->dmac_cmd_status); - pr_err("buf_addr=x%08x\n", descr->buf_addr); - pr_err("buf_size=x%08x\n", descr->buf_size); - pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr); - pr_err("result_size=x%08x\n", descr->result_size); - pr_err("valid_size=x%08x\n", descr->valid_size); - pr_err("data_status=x%08x\n", descr->data_status); - pr_err("data_error=x%08x\n", descr->data_error); - pr_err("bus_addr=x%08x\n", descr->bus_addr); + hwdescr->dmac_cmd_status); + pr_err("buf_addr=x%08x\n", hwdescr->buf_addr); + pr_err("buf_size=x%08x\n", hwdescr->buf_size); + pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr); + pr_err("result_size=x%08x\n", hwdescr->result_size); + pr_err("valid_size=x%08x\n", hwdescr->valid_size); + pr_err("data_status=x%08x\n", hwdescr->data_status); + pr_err("data_error=x%08x\n", hwdescr->data_error); pr_err("which=%ld\n", descr - card->rx_chain.ring); card->spider_stats.rx_desc_error++; @@ -1073,12 +1133,13 @@ spider_net_decode_one_descr(struct spider_net_card *card) /* Ok, we've got a packet in descr */ spider_net_pass_skb_up(descr, card); - descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; return 1; bad_desc: dev_kfree_skb_irq(descr->skb); - descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + descr->skb = NULL; + hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; return 0; } @@ -1248,6 +1309,33 @@ spider_net_set_mac(struct net_device *netdev, void *p) } /** + * spider_net_link_reset + * @netdev: net device structure + * + * This is called when the PHY_LINK signal is asserted. For the blade this is + * not connected so we should never get here. + * + */ +static void +spider_net_link_reset(struct net_device *netdev) +{ + + struct spider_net_card *card = netdev_priv(netdev); + + del_timer_sync(&card->aneg_timer); + + /* clear interrupt, block further interrupts */ + spider_net_write_reg(card, SPIDER_NET_GMACST, + spider_net_read_reg(card, SPIDER_NET_GMACST)); + spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0); + + /* reset phy and setup aneg */ + spider_net_setup_aneg(card); + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + +} + +/** * spider_net_handle_error_irq - handles errors raised by an interrupt * @card: card structure * @status_reg: interrupt status register 0 (GHIINT0STS) @@ -1359,8 +1447,8 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) switch (i) { case SPIDER_NET_GTMFLLINT: - if (netif_msg_intr(card) && net_ratelimit()) - pr_err("Spider TX RAM full\n"); + /* TX RAM full may happen on a usual case. + * Logging is not needed. */ show_error = 0; break; case SPIDER_NET_GRFDFLLINT: /* fallthrough */ @@ -1500,6 +1588,9 @@ spider_net_interrupt(int irq, void *ptr) if (status_reg & SPIDER_NET_TXINT) netif_rx_schedule(netdev); + if (status_reg & SPIDER_NET_LINKINT) + spider_net_link_reset(netdev); + if (status_reg & SPIDER_NET_ERRINT ) spider_net_handle_error_irq(card, status_reg); @@ -1540,6 +1631,11 @@ spider_net_init_card(struct spider_net_card *card) spider_net_write_reg(card, SPIDER_NET_CKRCTRL, SPIDER_NET_CKRCTRL_RUN_VALUE); + + /* trigger ETOMOD signal */ + spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, + spider_net_read_reg(card, SPIDER_NET_GMACOPEMD) | 0x4); + } /** @@ -1624,8 +1720,6 @@ spider_net_enable_card(struct spider_net_card *card) spider_net_write_reg(card, SPIDER_NET_GMACLENLMT, SPIDER_NET_LENLMT_VALUE); - spider_net_write_reg(card, SPIDER_NET_GMACMODE, - SPIDER_NET_MACMODE_VALUE); spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, SPIDER_NET_OPMODE_VALUE); @@ -1642,98 +1736,6 @@ spider_net_enable_card(struct spider_net_card *card) } /** - * spider_net_open - called upon ifonfig up - * @netdev: interface device structure - * - * returns 0 on success, <0 on failure - * - * spider_net_open allocates all the descriptors and memory needed for - * operation, sets up multicast list and enables interrupts - */ -int -spider_net_open(struct net_device *netdev) -{ - struct spider_net_card *card = netdev_priv(netdev); - int result; - - result = spider_net_init_chain(card, &card->tx_chain); - if (result) - goto alloc_tx_failed; - card->low_watermark = NULL; - - result = spider_net_init_chain(card, &card->rx_chain); - if (result) - goto alloc_rx_failed; - - /* Allocate rx skbs */ - if (spider_net_alloc_rx_skbs(card)) - goto alloc_skbs_failed; - - spider_net_set_multi(netdev); - - /* further enhancement: setup hw vlan, if needed */ - - result = -EBUSY; - if (request_irq(netdev->irq, spider_net_interrupt, - IRQF_SHARED, netdev->name, netdev)) - goto register_int_failed; - - spider_net_enable_card(card); - - netif_start_queue(netdev); - netif_carrier_on(netdev); - netif_poll_enable(netdev); - - return 0; - -register_int_failed: - spider_net_free_rx_chain_contents(card); -alloc_skbs_failed: - spider_net_free_chain(card, &card->rx_chain); -alloc_rx_failed: - spider_net_free_chain(card, &card->tx_chain); -alloc_tx_failed: - return result; -} - -/** - * spider_net_setup_phy - setup PHY - * @card: card structure - * - * returns 0 on success, <0 on failure - * - * spider_net_setup_phy is used as part of spider_net_probe. Sets - * the PHY to 1000 Mbps - **/ -static int -spider_net_setup_phy(struct spider_net_card *card) -{ - struct mii_phy *phy = &card->phy; - - spider_net_write_reg(card, SPIDER_NET_GDTDMASEL, - SPIDER_NET_DMASEL_VALUE); - spider_net_write_reg(card, SPIDER_NET_GPCCTRL, - SPIDER_NET_PHY_CTRL_VALUE); - phy->mii_id = 1; - phy->dev = card->netdev; - phy->mdio_read = spider_net_read_phy; - phy->mdio_write = spider_net_write_phy; - - mii_phy_probe(phy, phy->mii_id); - - if (phy->def->ops->setup_forced) - phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL); - - phy->def->ops->enable_fiber(phy); - - phy->def->ops->read_link(phy); - pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name, - phy->speed, phy->duplex==1 ? "Full" : "Half"); - - return 0; -} - -/** * spider_net_download_firmware - loads firmware into the adapter * @card: card structure * @firmware_ptr: pointer to firmware data @@ -1852,6 +1854,179 @@ out_err: } /** + * spider_net_open - called upon ifonfig up + * @netdev: interface device structure + * + * returns 0 on success, <0 on failure + * + * spider_net_open allocates all the descriptors and memory needed for + * operation, sets up multicast list and enables interrupts + */ +int +spider_net_open(struct net_device *netdev) +{ + struct spider_net_card *card = netdev_priv(netdev); + int result; + + result = spider_net_init_firmware(card); + if (result) + goto init_firmware_failed; + + /* start probing with copper */ + spider_net_setup_aneg(card); + if (card->phy.def->phy_id) + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + + result = spider_net_init_chain(card, &card->tx_chain); + if (result) + goto alloc_tx_failed; + card->low_watermark = NULL; + + result = spider_net_init_chain(card, &card->rx_chain); + if (result) + goto alloc_rx_failed; + + /* Allocate rx skbs */ + if (spider_net_alloc_rx_skbs(card)) + goto alloc_skbs_failed; + + spider_net_set_multi(netdev); + + /* further enhancement: setup hw vlan, if needed */ + + result = -EBUSY; + if (request_irq(netdev->irq, spider_net_interrupt, + IRQF_SHARED, netdev->name, netdev)) + goto register_int_failed; + + spider_net_enable_card(card); + + netif_start_queue(netdev); + netif_carrier_on(netdev); + netif_poll_enable(netdev); + + return 0; + +register_int_failed: + spider_net_free_rx_chain_contents(card); +alloc_skbs_failed: + spider_net_free_chain(card, &card->rx_chain); +alloc_rx_failed: + spider_net_free_chain(card, &card->tx_chain); +alloc_tx_failed: + del_timer_sync(&card->aneg_timer); +init_firmware_failed: + return result; +} + +/** + * spider_net_link_phy + * @data: used for pointer to card structure + * + */ +static void spider_net_link_phy(unsigned long data) +{ + struct spider_net_card *card = (struct spider_net_card *)data; + struct mii_phy *phy = &card->phy; + + /* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */ + if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) { + + pr_info("%s: link is down trying to bring it up\n", card->netdev->name); + + switch (card->medium) { + case BCM54XX_COPPER: + /* enable fiber with autonegotiation first */ + if (phy->def->ops->enable_fiber) + phy->def->ops->enable_fiber(phy, 1); + card->medium = BCM54XX_FIBER; + break; + + case BCM54XX_FIBER: + /* fiber didn't come up, try to disable fiber autoneg */ + if (phy->def->ops->enable_fiber) + phy->def->ops->enable_fiber(phy, 0); + card->medium = BCM54XX_UNKNOWN; + break; + + case BCM54XX_UNKNOWN: + /* copper, fiber with and without failed, + * retry from beginning */ + spider_net_setup_aneg(card); + card->medium = BCM54XX_COPPER; + break; + } + + card->aneg_count = 0; + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + return; + } + + /* link still not up, try again later */ + if (!(phy->def->ops->poll_link(phy))) { + card->aneg_count++; + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + return; + } + + /* link came up, get abilities */ + phy->def->ops->read_link(phy); + + spider_net_write_reg(card, SPIDER_NET_GMACST, + spider_net_read_reg(card, SPIDER_NET_GMACST)); + spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4); + + if (phy->speed == 1000) + spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001); + else + spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0); + + card->aneg_count = 0; + + pr_debug("Found %s with %i Mbps, %s-duplex %sautoneg.\n", + phy->def->name, phy->speed, phy->duplex==1 ? "Full" : "Half", + phy->autoneg==1 ? "" : "no "); + + return; +} + +/** + * spider_net_setup_phy - setup PHY + * @card: card structure + * + * returns 0 on success, <0 on failure + * + * spider_net_setup_phy is used as part of spider_net_probe. + **/ +static int +spider_net_setup_phy(struct spider_net_card *card) +{ + struct mii_phy *phy = &card->phy; + + spider_net_write_reg(card, SPIDER_NET_GDTDMASEL, + SPIDER_NET_DMASEL_VALUE); + spider_net_write_reg(card, SPIDER_NET_GPCCTRL, + SPIDER_NET_PHY_CTRL_VALUE); + + phy->dev = card->netdev; + phy->mdio_read = spider_net_read_phy; + phy->mdio_write = spider_net_write_phy; + + for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) { + unsigned short id; + id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR); + if (id != 0x0000 && id != 0xffff) { + if (!mii_phy_probe(phy, phy->mii_id)) { + pr_info("Found %s.\n", phy->def->name); + break; + } + } + } + + return 0; +} + +/** * spider_net_workaround_rxramfull - work around firmware bug * @card: card structure * @@ -1900,14 +2075,15 @@ spider_net_stop(struct net_device *netdev) netif_carrier_off(netdev); netif_stop_queue(netdev); del_timer_sync(&card->tx_timer); + del_timer_sync(&card->aneg_timer); /* disable/mask all interrupts */ spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0); spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0); spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0); + spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0); - /* free_irq(netdev->irq, netdev);*/ - free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev); + free_irq(netdev->irq, netdev); spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, SPIDER_NET_DMA_TX_FEND_VALUE); @@ -1919,8 +2095,6 @@ spider_net_stop(struct net_device *netdev) spider_net_release_tx_chain(card, 1); spider_net_free_rx_chain_contents(card); - spider_net_free_rx_chain_contents(card); - spider_net_free_chain(card, &card->tx_chain); spider_net_free_chain(card, &card->rx_chain); @@ -1952,8 +2126,6 @@ spider_net_tx_timeout_task(struct work_struct *work) if (spider_net_setup_phy(card)) goto out; - if (spider_net_init_firmware(card)) - goto out; spider_net_open(netdev); spider_net_kick_tx_dma(card); @@ -2046,10 +2218,12 @@ spider_net_setup_netdev(struct spider_net_card *card) card->tx_timer.data = (unsigned long) card; netdev->irq = card->pdev->irq; - card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; + card->aneg_count = 0; + init_timer(&card->aneg_timer); + card->aneg_timer.function = spider_net_link_phy; + card->aneg_timer.data = (unsigned long) card; - card->tx_chain.num_desc = tx_descriptors; - card->rx_chain.num_desc = rx_descriptors; + card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; spider_net_setup_netdev_ops(netdev); @@ -2098,8 +2272,11 @@ spider_net_alloc_card(void) { struct net_device *netdev; struct spider_net_card *card; + size_t alloc_size; - netdev = alloc_etherdev(sizeof(struct spider_net_card)); + alloc_size = sizeof(struct spider_net_card) + + (tx_descriptors + rx_descriptors) * sizeof(struct spider_net_descr); + netdev = alloc_etherdev(alloc_size); if (!netdev) return NULL; @@ -2110,6 +2287,11 @@ spider_net_alloc_card(void) init_waitqueue_head(&card->waitq); atomic_set(&card->tx_timeout_task_counter, 0); + card->rx_chain.num_desc = rx_descriptors; + card->rx_chain.ring = card->darray; + card->tx_chain.num_desc = tx_descriptors; + card->tx_chain.ring = card->darray + rx_descriptors; + return card; } @@ -2220,10 +2402,6 @@ spider_net_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_undo_pci; - err = spider_net_init_firmware(card); - if (err) - goto out_undo_pci; - err = spider_net_setup_netdev(card); if (err) goto out_undo_pci; diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 2fec5cf7692..4a1e0d28a50 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -1,7 +1,8 @@ /* - * Network device driver for Cell Processor-Based Blade + * Network device driver for Cell Processor-Based Blade and Celleb platform * * (C) Copyright IBM Corp. 2005 + * (C) Copyright 2006 TOSHIBA CORPORATION * * Authors : Utz Bacher <utz.bacher@de.ibm.com> * Jens Osterkamp <Jens.Osterkamp@de.ibm.com> @@ -24,7 +25,7 @@ #ifndef _SPIDER_NET_H #define _SPIDER_NET_H -#define VERSION "1.6 B" +#define VERSION "2.0 A" #include "sungem_phy.h" @@ -50,6 +51,8 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_TX_DESCRIPTORS_MAX 512 #define SPIDER_NET_TX_TIMER (HZ/5) +#define SPIDER_NET_ANEG_TIMER (HZ) +#define SPIDER_NET_ANEG_TIMEOUT 2 #define SPIDER_NET_RX_CSUM_DEFAULT 1 @@ -104,6 +107,7 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_GMACOPEMD 0x00000100 #define SPIDER_NET_GMACLENLMT 0x00000108 +#define SPIDER_NET_GMACST 0x00000110 #define SPIDER_NET_GMACINTEN 0x00000118 #define SPIDER_NET_GMACPHYCTRL 0x00000120 @@ -181,7 +185,8 @@ extern char spider_net_driver_name[]; /* pause frames: automatic, no upper retransmission count */ /* outside loopback mode: ETOMOD signal dont matter, not connected */ -#define SPIDER_NET_OPMODE_VALUE 0x00000063 +/* ETOMOD signal is brought to PHY reset. bit 2 must be 1 in Celleb */ +#define SPIDER_NET_OPMODE_VALUE 0x00000067 /*#define SPIDER_NET_OPMODE_VALUE 0x001b0062*/ #define SPIDER_NET_LENLMT_VALUE 0x00000908 @@ -333,9 +338,12 @@ enum spider_net_int2_status { /* We rely on flagged descriptor interrupts */ #define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) +#define SPIDER_NET_LINKINT ( 1 << SPIDER_NET_GMAC2INT ) + #define SPIDER_NET_ERRINT ( 0xffffffff & \ (~SPIDER_NET_TXINT) & \ - (~SPIDER_NET_RXINT) ) + (~SPIDER_NET_RXINT) & \ + (~SPIDER_NET_LINKINT) ) #define SPIDER_NET_GPREXEC 0x80000000 #define SPIDER_NET_GPRDAT_MASK 0x0000ffff @@ -356,8 +364,8 @@ enum spider_net_int2_status { #define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000 #define SPIDER_NET_DESCR_TXDESFLG 0x00800000 -struct spider_net_descr { - /* as defined by the hardware */ +/* Descriptor, as defined by the hardware */ +struct spider_net_hw_descr { u32 buf_addr; u32 buf_size; u32 next_descr_addr; @@ -366,13 +374,15 @@ struct spider_net_descr { u32 valid_size; /* all zeroes for tx */ u32 data_status; u32 data_error; /* all zeroes for tx */ +} __attribute__((aligned(32))); - /* used in the driver */ +struct spider_net_descr { + struct spider_net_hw_descr *hwdescr; struct sk_buff *skb; u32 bus_addr; struct spider_net_descr *next; struct spider_net_descr *prev; -} __attribute__((aligned(32))); +}; struct spider_net_descr_chain { spinlock_t lock; @@ -380,6 +390,7 @@ struct spider_net_descr_chain { struct spider_net_descr *tail; struct spider_net_descr *ring; int num_desc; + struct spider_net_hw_descr *hwring; dma_addr_t dma_addr; }; @@ -436,12 +447,16 @@ struct spider_net_card { struct pci_dev *pdev; struct mii_phy phy; + int medium; + void __iomem *regs; struct spider_net_descr_chain tx_chain; struct spider_net_descr_chain rx_chain; struct spider_net_descr *low_watermark; + int aneg_count; + struct timer_list aneg_timer; struct timer_list tx_timer; struct work_struct tx_timeout_task; atomic_t tx_timeout_task_counter; @@ -452,6 +467,9 @@ struct spider_net_card { struct net_device_stats netdev_stats; struct spider_net_extra_stats spider_stats; struct spider_net_options options; + + /* Must be last item in struct */ + struct spider_net_descr darray[0]; }; #define pr_err(fmt,arg...) \ diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index bf873ea2579..8bba2e3da7e 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -677,8 +677,7 @@ static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) spin_lock(&np->lock); if (debug > 1) printk("%s: removing vlanid %d from vlan filter\n", dev->name, vid); - if (np->vlgrp) - np->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(np->vlgrp, vid, NULL); set_rx_mode(dev); spin_unlock(&np->lock); } @@ -1738,7 +1737,7 @@ static void set_rx_mode(struct net_device *dev) int vlan_count = 0; void __iomem *filter_addr = ioaddr + HashTable + 8; for (i = 0; i < VLAN_VID_MASK; i++) { - if (np->vlgrp->vlan_devices[i]) { + if (vlan_group_get_device(np->vlgrp, i)) { if (vlan_count >= 32) break; writew(cpu_to_be16(i), filter_addr); diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index a3220a96524..4757aa647c7 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -28,8 +28,6 @@ static int automatic_resume = 0; /* experimental .. better should be zero */ static int rfdadd = 0; /* rfdadd=1 may be better for 8K MEM cards */ static int fifo=0x8; /* don't change */ -/* #define REALLY_SLOW_IO */ - #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index 701ba4f3b69..56a110ca5e6 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -310,6 +310,107 @@ static int bcm5411_init(struct mii_phy* phy) return 0; } +static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) +{ + u16 ctl, adv; + + phy->autoneg = 1; + phy->speed = SPEED_10; + phy->duplex = DUPLEX_HALF; + phy->pause = 0; + phy->advertising = advertise; + + /* Setup standard advertise */ + adv = phy_read(phy, MII_ADVERTISE); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + 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; + phy_write(phy, MII_ADVERTISE, adv); + + /* Start/Restart aneg */ + ctl = phy_read(phy, MII_BMCR); + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) +{ + u16 ctl; + + phy->autoneg = 0; + phy->speed = speed; + phy->duplex = fd; + phy->pause = 0; + + ctl = phy_read(phy, MII_BMCR); + ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE); + + /* First reset the PHY */ + phy_write(phy, MII_BMCR, ctl | BMCR_RESET); + + /* Select speed & duplex */ + switch(speed) { + case SPEED_10: + break; + case SPEED_100: + ctl |= BMCR_SPEED100; + break; + case SPEED_1000: + default: + return -EINVAL; + } + if (fd == DUPLEX_FULL) + ctl |= BMCR_FULLDPLX; + phy_write(phy, MII_BMCR, ctl); + + return 0; +} + +static int genmii_poll_link(struct mii_phy *phy) +{ + u16 status; + + (void)phy_read(phy, MII_BMSR); + status = phy_read(phy, MII_BMSR); + if ((status & BMSR_LSTATUS) == 0) + return 0; + if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE)) + return 0; + return 1; +} + +static int genmii_read_link(struct mii_phy *phy) +{ + u16 lpa; + + if (phy->autoneg) { + lpa = phy_read(phy, MII_LPA); + + if (lpa & (LPA_10FULL | LPA_100FULL)) + phy->duplex = DUPLEX_FULL; + else + phy->duplex = DUPLEX_HALF; + if (lpa & (LPA_100FULL | LPA_100HALF)) + phy->speed = SPEED_100; + else + phy->speed = SPEED_10; + phy->pause = 0; + } + /* On non-aneg, we assume what we put in BMCR is the speed, + * though magic-aneg shouldn't prevent this case from occurring + */ + + return 0; +} + static int generic_suspend(struct mii_phy* phy) { phy_write(phy, MII_BMCR, BMCR_PDOWN); @@ -364,30 +465,6 @@ static int bcm5421_init(struct mii_phy* phy) return 0; } -static int bcm5421_enable_fiber(struct mii_phy* phy) -{ - /* enable fiber mode */ - phy_write(phy, MII_NCONFIG, 0x9020); - /* LEDs active in both modes, autosense prio = fiber */ - phy_write(phy, MII_NCONFIG, 0x945f); - - /* switch off fibre autoneg */ - phy_write(phy, MII_NCONFIG, 0xfc01); - phy_write(phy, 0x0b, 0x0004); - - return 0; -} - -static int bcm5461_enable_fiber(struct mii_phy* phy) -{ - phy_write(phy, MII_NCONFIG, 0xfc0c); - phy_write(phy, MII_BMCR, 0x4140); - phy_write(phy, MII_NCONFIG, 0xfc0b); - phy_write(phy, MII_BMCR, 0x0140); - - return 0; -} - static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise) { u16 ctl, adv; @@ -515,6 +592,155 @@ static int marvell88e1111_init(struct mii_phy* phy) return 0; } +#define BCM5421_MODE_MASK (1 << 5) + +static int bcm5421_poll_link(struct mii_phy* phy) +{ + u32 phy_reg; + int mode; + + /* find out in what mode we are */ + phy_write(phy, MII_NCONFIG, 0x1000); + phy_reg = phy_read(phy, MII_NCONFIG); + + mode = (phy_reg & BCM5421_MODE_MASK) >> 5; + + if ( mode == BCM54XX_COPPER) + return genmii_poll_link(phy); + + /* try to find out wether we have a link */ + phy_write(phy, MII_NCONFIG, 0x2000); + phy_reg = phy_read(phy, MII_NCONFIG); + + if (phy_reg & 0x0020) + return 0; + else + return 1; +} + +static int bcm5421_read_link(struct mii_phy* phy) +{ + u32 phy_reg; + int mode; + + /* find out in what mode we are */ + phy_write(phy, MII_NCONFIG, 0x1000); + phy_reg = phy_read(phy, MII_NCONFIG); + + mode = (phy_reg & BCM5421_MODE_MASK ) >> 5; + + if ( mode == BCM54XX_COPPER) + return bcm54xx_read_link(phy); + + phy->speed = SPEED_1000; + + /* find out wether we are running half- or full duplex */ + phy_write(phy, MII_NCONFIG, 0x2000); + phy_reg = phy_read(phy, MII_NCONFIG); + + if ( (phy_reg & 0x0080) >> 7) + phy->duplex |= DUPLEX_HALF; + else + phy->duplex |= DUPLEX_FULL; + + return 0; +} + +static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg) +{ + /* enable fiber mode */ + phy_write(phy, MII_NCONFIG, 0x9020); + /* LEDs active in both modes, autosense prio = fiber */ + phy_write(phy, MII_NCONFIG, 0x945f); + + if (!autoneg) { + /* switch off fibre autoneg */ + phy_write(phy, MII_NCONFIG, 0xfc01); + phy_write(phy, 0x0b, 0x0004); + } + + phy->autoneg = autoneg; + + return 0; +} + +#define BCM5461_FIBER_LINK (1 << 2) +#define BCM5461_MODE_MASK (3 << 1) + +static int bcm5461_poll_link(struct mii_phy* phy) +{ + u32 phy_reg; + int mode; + + /* find out in what mode we are */ + phy_write(phy, MII_NCONFIG, 0x7c00); + phy_reg = phy_read(phy, MII_NCONFIG); + + mode = (phy_reg & BCM5461_MODE_MASK ) >> 1; + + if ( mode == BCM54XX_COPPER) + return genmii_poll_link(phy); + + /* find out wether we have a link */ + phy_write(phy, MII_NCONFIG, 0x7000); + phy_reg = phy_read(phy, MII_NCONFIG); + + if (phy_reg & BCM5461_FIBER_LINK) + return 1; + else + return 0; +} + +#define BCM5461_FIBER_DUPLEX (1 << 3) + +static int bcm5461_read_link(struct mii_phy* phy) +{ + u32 phy_reg; + int mode; + + /* find out in what mode we are */ + phy_write(phy, MII_NCONFIG, 0x7c00); + phy_reg = phy_read(phy, MII_NCONFIG); + + mode = (phy_reg & BCM5461_MODE_MASK ) >> 1; + + if ( mode == BCM54XX_COPPER) { + return bcm54xx_read_link(phy); + } + + phy->speed = SPEED_1000; + + /* find out wether we are running half- or full duplex */ + phy_write(phy, MII_NCONFIG, 0x7000); + phy_reg = phy_read(phy, MII_NCONFIG); + + if (phy_reg & BCM5461_FIBER_DUPLEX) + phy->duplex |= DUPLEX_FULL; + else + phy->duplex |= DUPLEX_HALF; + + return 0; +} + +static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg) +{ + /* select fiber mode, enable 1000 base-X registers */ + phy_write(phy, MII_NCONFIG, 0xfc0b); + + if (autoneg) { + /* enable fiber with no autonegotiation */ + phy_write(phy, MII_ADVERTISE, 0x01e0); + phy_write(phy, MII_BMCR, 0x1140); + } else { + /* enable fiber with autonegotiation */ + phy_write(phy, MII_BMCR, 0x0140); + } + + phy->autoneg = autoneg; + + return 0; +} + static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise) { u16 ctl, adv; @@ -645,113 +871,6 @@ static int marvell_read_link(struct mii_phy *phy) return 0; } -static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) -{ - u16 ctl, adv; - - phy->autoneg = 1; - phy->speed = SPEED_10; - phy->duplex = DUPLEX_HALF; - phy->pause = 0; - phy->advertising = advertise; - - /* Setup standard advertise */ - adv = phy_read(phy, MII_ADVERTISE); - adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); - 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; - phy_write(phy, MII_ADVERTISE, adv); - - /* Start/Restart aneg */ - ctl = phy_read(phy, MII_BMCR); - ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); - phy_write(phy, MII_BMCR, ctl); - - return 0; -} - -static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd) -{ - u16 ctl; - - phy->autoneg = 0; - phy->speed = speed; - phy->duplex = fd; - phy->pause = 0; - - ctl = phy_read(phy, MII_BMCR); - ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE); - - /* First reset the PHY */ - phy_write(phy, MII_BMCR, ctl | BMCR_RESET); - - /* Select speed & duplex */ - switch(speed) { - case SPEED_10: - break; - case SPEED_100: - ctl |= BMCR_SPEED100; - break; - case SPEED_1000: - default: - return -EINVAL; - } - if (fd == DUPLEX_FULL) - ctl |= BMCR_FULLDPLX; - phy_write(phy, MII_BMCR, ctl); - - return 0; -} - -static int genmii_poll_link(struct mii_phy *phy) -{ - u16 status; - - (void)phy_read(phy, MII_BMSR); - status = phy_read(phy, MII_BMSR); - if ((status & BMSR_LSTATUS) == 0) - return 0; - if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE)) - return 0; - return 1; -} - -static int genmii_read_link(struct mii_phy *phy) -{ - u16 lpa; - - if (phy->autoneg) { - lpa = phy_read(phy, MII_LPA); - - if (lpa & (LPA_10FULL | LPA_100FULL)) - phy->duplex = DUPLEX_FULL; - else - phy->duplex = DUPLEX_HALF; - if (lpa & (LPA_100FULL | LPA_100HALF)) - phy->speed = SPEED_100; - else - phy->speed = SPEED_10; - phy->pause = (phy->duplex == DUPLEX_FULL) && - ((lpa & LPA_PAUSE) != 0); - } - /* On non-aneg, we assume what we put in BMCR is the speed, - * though magic-aneg shouldn't prevent this case from occurring - */ - - return 0; -} - - #define MII_BASIC_FEATURES \ (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \ SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \ @@ -885,8 +1004,8 @@ static struct mii_phy_ops bcm5421_phy_ops = { .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, - .poll_link = genmii_poll_link, - .read_link = bcm54xx_read_link, + .poll_link = bcm5421_poll_link, + .read_link = bcm5421_read_link, .enable_fiber = bcm5421_enable_fiber, }; @@ -923,8 +1042,8 @@ static struct mii_phy_ops bcm5461_phy_ops = { .suspend = generic_suspend, .setup_aneg = bcm54xx_setup_aneg, .setup_forced = bcm54xx_setup_forced, - .poll_link = genmii_poll_link, - .read_link = bcm54xx_read_link, + .poll_link = bcm5461_poll_link, + .read_link = bcm5461_read_link, .enable_fiber = bcm5461_enable_fiber, }; diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h index 1d70ba6f9f1..af02f9479cb 100644 --- a/drivers/net/sungem_phy.h +++ b/drivers/net/sungem_phy.h @@ -12,7 +12,7 @@ struct mii_phy_ops int (*setup_forced)(struct mii_phy *phy, int speed, int fd); int (*poll_link)(struct mii_phy *phy); int (*read_link)(struct mii_phy *phy); - int (*enable_fiber)(struct mii_phy *phy); + int (*enable_fiber)(struct mii_phy *phy, int autoneg); }; /* Structure used to statically define an mii/gii based PHY */ @@ -26,6 +26,14 @@ struct mii_phy_def const struct mii_phy_ops* ops; }; +enum { + BCM54XX_COPPER, + BCM54XX_FIBER, + BCM54XX_GBIC, + BCM54XX_SGMII, + BCM54XX_UNKNOWN, +}; + /* An instance of a PHY, partially borrowed from mii_if_info */ struct mii_phy { diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index 81ed82f0b52..e3a7e3ceab7 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -657,7 +657,7 @@ tc35815_init_queues(struct net_device *dev) dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); #endif } else { - clear_page(lp->fd_buf); + memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM); #ifdef __mips__ dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); #endif @@ -1703,19 +1703,6 @@ static void tc35815_chip_init(struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); } -/* XXX */ -void -tc35815_killall(void) -{ - struct net_device *dev; - - for (dev = root_tc35815_dev; dev; dev = ((struct tc35815_local *)dev->priv)->next_module) { - if (dev->flags&IFF_UP){ - dev->stop(dev); - } - } -} - static struct pci_driver tc35815_driver = { .name = TC35815_MODULE_NAME, .probe = tc35815_probe, @@ -1732,6 +1719,11 @@ static void __exit tc35815_cleanup_module(void) { struct net_device *next_dev; + /* + * TODO: implement a tc35815_driver.remove hook, and + * move this code into that function. Then, delete + * all root_tc35815_dev list handling code. + */ while (root_tc35815_dev) { struct net_device *dev = root_tc35815_dev; next_dev = ((struct tc35815_local *)dev->priv)->next_module; @@ -1740,6 +1732,9 @@ static void __exit tc35815_cleanup_module(void) free_netdev(dev); root_tc35815_dev = next_dev; } + + pci_unregister_driver(&tc35815_driver); } + module_init(tc35815_init_module); module_exit(tc35815_cleanup_module); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 81a1c2e1a3f..8c8f9f4d47a 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.73" -#define DRV_MODULE_RELDATE "February 12, 2007" +#define DRV_MODULE_VERSION "3.74" +#define DRV_MODULE_RELDATE "February 20, 2007" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -3993,7 +3993,10 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) /* Estimate the number of fragments in the worst case */ if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) { netif_stop_queue(tp->dev); - return NETDEV_TX_BUSY; + if (tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3)) + return NETDEV_TX_BUSY; + + netif_wake_queue(tp->dev); } segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO); @@ -4061,7 +4064,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) hdr_len = ip_tcp_len + tcp_opt_len; if (unlikely((ETH_HLEN + hdr_len) > 80) && - (tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG)) + (tp->tg3_flags2 & TG3_FLG2_TSO_BUG)) return (tg3_tso_bug(tp, skb)); base_flags |= (TXD_FLAG_CPU_PRE_DMA | @@ -8137,7 +8140,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e (ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) || (ering->tx_pending > TG3_TX_RING_SIZE - 1) || (ering->tx_pending <= MAX_SKB_FRAGS) || - ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) && + ((tp->tg3_flags2 & TG3_FLG2_TSO_BUG) && (ering->tx_pending <= (MAX_SKB_FRAGS * 3)))) return -EINVAL; @@ -9111,8 +9114,7 @@ static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) tg3_netif_stop(tp); tg3_full_lock(tp, 0); - if (tp->vlgrp) - tp->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(tp->vlgrp, vid, NULL); tg3_full_unlock(tp); if (netif_running(dev)) @@ -10557,12 +10559,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; } else { - tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | - TG3_FLG2_HW_TSO_1_BUG; + tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | TG3_FLG2_TSO_BUG; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 && tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2) - tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_1_BUG; + tp->tg3_flags2 &= ~TG3_FLG2_TSO_BUG; } } @@ -11867,7 +11868,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) { tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE; } else { - tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; + tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE | TG3_FLG2_TSO_BUG; } /* TSO is on by default on chips that support hardware TSO. diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 45d477e8f37..086892d8c1f 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2227,7 +2227,7 @@ struct tg3 { #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 tg3_flags2; #define TG3_FLG2_RESTART_TIMER 0x00000001 -#define TG3_FLG2_HW_TSO_1_BUG 0x00000002 +#define TG3_FLG2_TSO_BUG 0x00000002 #define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004 #define TG3_FLG2_IS_5788 0x00000008 #define TG3_FLG2_MAX_RXPEND_64 0x00000010 diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 0d97e10ccac..36202e94ee9 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -186,7 +186,6 @@ static char __devinit *adapter_def(char type) #define TRC_INITV 0x02 /* verbose init trace points */ static unsigned char ibmtr_debug_trace = 0; -static int ibmtr_probe(struct net_device *dev); static int ibmtr_probe1(struct net_device *dev, int ioaddr); static unsigned char get_sram_size(struct tok_info *adapt_info); static int trdev_init(struct net_device *dev); @@ -335,17 +334,6 @@ static void ibmtr_cleanup_card(struct net_device *dev) #endif } -int ibmtr_probe_card(struct net_device *dev) -{ - int err = ibmtr_probe(dev); - if (!err) { - err = register_netdev(dev); - if (err) - ibmtr_cleanup_card(dev); - } - return err; -} - /**************************************************************************** * ibmtr_probe(): Routine specified in the network device structure * to probe for an IBM Token Ring Adapter. Routine outline: @@ -358,7 +346,7 @@ int ibmtr_probe_card(struct net_device *dev) * which references it. ****************************************************************************/ -static int ibmtr_probe(struct net_device *dev) +static int __init ibmtr_probe(struct net_device *dev) { int i; int base_addr = dev->base_addr; @@ -378,6 +366,17 @@ static int ibmtr_probe(struct net_device *dev) return -ENODEV; } +int __init ibmtr_probe_card(struct net_device *dev) +{ + int err = ibmtr_probe(dev); + if (!err) { + err = register_netdev(dev); + if (err) + ibmtr_cleanup_card(dev); + } + return err; +} + /*****************************************************************************/ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 9d67f11422e..c82befa209a 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -63,7 +63,7 @@ MODULE_PARM_DESC (debug, "de2104x bitmapped message enable number"); /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(__sparc_) || defined(__ia64__) \ + || defined(__sparc__) || defined(__ia64__) \ || defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else @@ -1685,7 +1685,7 @@ static const struct ethtool_ops de_ethtool_ops = { .get_regs = de_get_regs, }; -static void __init de21040_get_mac_address (struct de_private *de) +static void __devinit de21040_get_mac_address (struct de_private *de) { unsigned i; @@ -1703,7 +1703,7 @@ static void __init de21040_get_mac_address (struct de_private *de) } } -static void __init de21040_get_media_info(struct de_private *de) +static void __devinit de21040_get_media_info(struct de_private *de) { unsigned int i; @@ -1765,7 +1765,7 @@ static unsigned __devinit tulip_read_eeprom(void __iomem *regs, int location, in return retval; } -static void __init de21041_get_srom_info (struct de_private *de) +static void __devinit de21041_get_srom_info (struct de_private *de) { unsigned i, sa_offset = 0, ofs; u8 ee_data[DE_EEPROM_SIZE + 6] = {}; diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 7f59a3d4fda..24a29c99ba9 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -143,9 +143,16 @@ #define DMFE_TX_TIMEOUT ((3*HZ)/2) /* tx packet time-out time 1.5 s" */ #define DMFE_TX_KICK (HZ/2) /* tx packet Kick-out time 0.5 s" */ -#define DMFE_DBUG(dbug_now, msg, value) if (dmfe_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value)) +#define DMFE_DBUG(dbug_now, msg, value) \ + do { \ + if (dmfe_debug || (dbug_now)) \ + printk(KERN_ERR DRV_NAME ": %s %lx\n",\ + (msg), (long) (value)); \ + } while (0) -#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); +#define SHOW_MEDIA_TYPE(mode) \ + printk (KERN_INFO DRV_NAME ": Change Speed to %sMhz %s duplex\n" , \ + (mode & 1) ? "100":"10", (mode & 4) ? "full":"half"); /* CR9 definition: SROM/MII */ @@ -163,10 +170,20 @@ #define SROM_V41_CODE 0x14 -#define SROM_CLK_WRITE(data, ioaddr) outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr);udelay(5);outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr);udelay(5); +#define SROM_CLK_WRITE(data, ioaddr) \ + outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr); \ + udelay(5); \ + outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr); \ + udelay(5); \ + outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr); \ + udelay(5); + +#define __CHK_IO_SIZE(pci_id, dev_rev) \ + (( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? \ + DM9102A_IO_SIZE: DM9102_IO_SIZE) -#define __CHK_IO_SIZE(pci_id, dev_rev) ( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? DM9102A_IO_SIZE: DM9102_IO_SIZE -#define CHK_IO_SIZE(pci_dev, dev_rev) __CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev) +#define CHK_IO_SIZE(pci_dev, dev_rev) \ + (__CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev)) /* Sten Check */ #define DEVICE net_device @@ -187,7 +204,7 @@ struct rx_desc { struct dmfe_board_info { u32 chip_id; /* Chip vendor/Device ID */ u32 chip_revision; /* Chip revision */ - struct DEVICE *dev; /* net device */ + struct DEVICE *next_dev; /* next device */ struct pci_dev *pdev; /* PCI device */ spinlock_t lock; @@ -231,7 +248,6 @@ struct dmfe_board_info { u8 media_mode; /* user specify media mode */ u8 op_mode; /* real work media mode */ u8 phy_addr; - u8 link_failed; /* Ever link failed */ u8 wait_reset; /* Hardware failed, need to reset */ u8 dm910x_chk_mode; /* Operating mode check */ u8 first_in_callback; /* Flag to record state */ @@ -329,7 +345,7 @@ static void dmfe_program_DM9802(struct dmfe_board_info *); static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * ); static void dmfe_set_phyxcer(struct dmfe_board_info *); -/* DM910X network baord routine ---------------------------- */ +/* DM910X network board routine ---------------------------- */ /* * Search DM910X board ,allocate space and register it @@ -356,7 +372,8 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { - printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n"); + printk(KERN_WARNING DRV_NAME + ": 32-bit PCI DMA not available.\n"); err = -ENODEV; goto err_out_free; } @@ -399,11 +416,12 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, /* Init system & device */ db = netdev_priv(dev); - db->dev = dev; - /* Allocate Tx/Rx descriptor memory */ - db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr); - db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr); + db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * + DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr); + + db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * + TX_DESC_CNT + 4, &db->buf_pool_dma_ptr); db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr; db->first_tx_desc_dma = db->desc_pool_dma_ptr; @@ -428,7 +446,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, dev->poll_controller = &poll_dmfe; #endif dev->ethtool_ops = &netdev_ethtool_ops; - netif_carrier_off(db->dev); + netif_carrier_off(dev); spin_lock_init(&db->lock); pci_read_config_dword(pdev, 0x50, &pci_pmr); @@ -440,7 +458,8 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, /* read 64 word srom data */ for (i = 0; i < 64; i++) - ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i)); + ((u16 *) db->srom)[i] = + cpu_to_le16(read_srom_word(db->ioaddr, i)); /* Set Node address */ for (i = 0; i < 6; i++) @@ -482,14 +501,17 @@ static void __devexit dmfe_remove_one (struct pci_dev *pdev) DMFE_DBUG(0, "dmfe_remove_one()", 0); if (dev) { + + unregister_netdev(dev); + pci_free_consistent(db->pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, db->desc_pool_ptr, db->desc_pool_dma_ptr); pci_free_consistent(db->pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, db->buf_pool_ptr, db->buf_pool_dma_ptr); - unregister_netdev(dev); pci_release_regions(pdev); free_netdev(dev); /* free board information */ + pci_set_drvdata(pdev, NULL); } @@ -509,7 +531,8 @@ static int dmfe_open(struct DEVICE *dev) DMFE_DBUG(0, "dmfe_open", 0); - ret = request_irq(dev->irq, &dmfe_interrupt, IRQF_SHARED, dev->name, dev); + ret = request_irq(dev->irq, &dmfe_interrupt, + IRQF_SHARED, dev->name, dev); if (ret) return ret; @@ -518,7 +541,6 @@ static int dmfe_open(struct DEVICE *dev) db->tx_packet_cnt = 0; db->tx_queue_cnt = 0; db->rx_avail_cnt = 0; - db->link_failed = 1; db->wait_reset = 0; db->first_in_callback = 0; @@ -650,7 +672,8 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) /* No Tx resource check, it never happen nromally */ if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) { spin_unlock_irqrestore(&db->lock, flags); - printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt); + printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", + db->tx_queue_cnt); return 1; } @@ -722,7 +745,8 @@ static int dmfe_stop(struct DEVICE *dev) #if 0 /* show statistic counter */ - printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", + printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx" + " LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", db->tx_fifo_underrun, db->tx_excessive_collision, db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, db->tx_jabber_timeout, db->reset_count, db->reset_cr8, @@ -905,7 +929,7 @@ static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag) static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) { struct rx_desc *rxptr; - struct sk_buff *skb; + struct sk_buff *skb, *newskb; int rxlen; u32 rdes0; @@ -919,7 +943,9 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) db->rx_avail_cnt--; db->interval_rx_cnt++; - pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE); + pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), + RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE); + if ( (rdes0 & 0x300) != 0x300) { /* A packet without First/Last flag */ /* reuse this SKB */ @@ -956,9 +982,11 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) } else { /* Good packet, send to upper layer */ /* Shorst packet used new SKB */ - if ( (rxlen < RX_COPY_SIZE) && - ( (skb = dev_alloc_skb(rxlen + 2) ) - != NULL) ) { + if ((rxlen < RX_COPY_SIZE) && + ((newskb = dev_alloc_skb(rxlen + 2)) + != NULL)) { + + skb = newskb; /* size less than COPY_SIZE, allocate a rxlen SKB */ skb->dev = dev; skb_reserve(skb, 2); /* 16byte align */ @@ -1069,6 +1097,8 @@ static void dmfe_timer(unsigned long data) struct dmfe_board_info *db = netdev_priv(dev); unsigned long flags; + int link_ok, link_ok_phy; + DMFE_DBUG(0, "dmfe_timer()", 0); spin_lock_irqsave(&db->lock, flags); @@ -1078,7 +1108,8 @@ static void dmfe_timer(unsigned long data) if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) { db->cr6_data &= ~0x40000; update_cr6(db->cr6_data, db->ioaddr); - phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id); + phy_write(db->ioaddr, + db->phy_addr, 0, 0x1000, db->chip_id); db->cr6_data |= 0x40000; update_cr6(db->cr6_data, db->ioaddr); db->timer.expires = DMFE_TIMER_WUT + HZ * 2; @@ -1139,21 +1170,41 @@ static void dmfe_timer(unsigned long data) (db->chip_revision == 0x02000010)) ) { /* DM9102A Chip */ if (tmp_cr12 & 2) - tmp_cr12 = 0x0; /* Link failed */ + link_ok = 0; else - tmp_cr12 = 0x3; /* Link OK */ + link_ok = 1; } + else + /*0x43 is used instead of 0x3 because bit 6 should represent + link status of external PHY */ + link_ok = (tmp_cr12 & 0x43) ? 1 : 0; + + + /* If chip reports that link is failed it could be because external + PHY link status pin is not conected correctly to chip + To be sure ask PHY too. + */ + + /* need a dummy read because of PHY's register latch*/ + phy_read (db->ioaddr, db->phy_addr, 1, db->chip_id); + link_ok_phy = (phy_read (db->ioaddr, + db->phy_addr, 1, db->chip_id) & 0x4) ? 1 : 0; - if ( !(tmp_cr12 & 0x3) && !db->link_failed ) { + if (link_ok_phy != link_ok) { + DMFE_DBUG (0, "PHY and chip report different link status", 0); + link_ok = link_ok | link_ok_phy; + } + + if ( !link_ok && netif_carrier_ok(dev)) { /* Link Failed */ DMFE_DBUG(0, "Link Failed", tmp_cr12); - db->link_failed = 1; - netif_carrier_off(db->dev); + netif_carrier_off(dev); /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */ /* AUTO or force 1M Homerun/Longrun don't need */ if ( !(db->media_mode & 0x38) ) - phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id); + phy_write(db->ioaddr, db->phy_addr, + 0, 0x1000, db->chip_id); /* AUTO mode, if INT phyxcer link failed, select EXT device */ if (db->media_mode & DMFE_AUTO) { @@ -1162,21 +1213,19 @@ static void dmfe_timer(unsigned long data) db->cr6_data&=~0x00000200; /* bit9=0, HD mode */ update_cr6(db->cr6_data, db->ioaddr); } - } else - if ((tmp_cr12 & 0x3) && db->link_failed) { - DMFE_DBUG(0, "Link link OK", tmp_cr12); - db->link_failed = 0; - - /* Auto Sense Speed */ - if ( (db->media_mode & DMFE_AUTO) && - dmfe_sense_speed(db) ) - db->link_failed = 1; - else - netif_carrier_on(db->dev); - dmfe_process_mode(db); - /* SHOW_MEDIA_TYPE(db->op_mode); */ + } else if (!netif_carrier_ok(dev)) { + + DMFE_DBUG(0, "Link link OK", tmp_cr12); + + /* Auto Sense Speed */ + if ( !(db->media_mode & DMFE_AUTO) || !dmfe_sense_speed(db)) { + netif_carrier_on(dev); + SHOW_MEDIA_TYPE(db->op_mode); } + dmfe_process_mode(db); + } + /* HPNA remote command check */ if (db->HPNA_command & 0xf00) { db->HPNA_timer--; @@ -1221,7 +1270,7 @@ static void dmfe_dynamic_reset(struct DEVICE *dev) db->tx_packet_cnt = 0; db->tx_queue_cnt = 0; db->rx_avail_cnt = 0; - db->link_failed = 1; + netif_carrier_off(dev); db->wait_reset = 0; /* Re-initilize DM910X board */ @@ -1259,7 +1308,8 @@ static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb) if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) { rxptr->rx_skb_ptr = skb; - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, + skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); db->rx_avail_cnt++; @@ -1291,8 +1341,11 @@ static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioadd outl(db->first_tx_desc_dma, ioaddr + DCR4); /* TX DESC address */ /* rx descriptor start pointer */ - db->first_rx_desc = (void *)db->first_tx_desc + sizeof(struct tx_desc) * TX_DESC_CNT; - db->first_rx_desc_dma = db->first_tx_desc_dma + sizeof(struct tx_desc) * TX_DESC_CNT; + db->first_rx_desc = (void *)db->first_tx_desc + + sizeof(struct tx_desc) * TX_DESC_CNT; + + db->first_rx_desc_dma = db->first_tx_desc_dma + + sizeof(struct tx_desc) * TX_DESC_CNT; db->rx_insert_ptr = db->first_rx_desc; db->rx_ready_ptr = db->first_rx_desc; outl(db->first_rx_desc_dma, ioaddr + DCR3); /* RX DESC address */ @@ -1470,7 +1523,8 @@ static void allocate_rx_buffer(struct dmfe_board_info *db) if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL ) break; rxptr->rx_skb_ptr = skb; /* FIXME (?) */ - rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, + RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); wmb(); rxptr->rdes0 = cpu_to_le32(0x80000000); rxptr = rxptr->next_rx_desc; @@ -1510,7 +1564,8 @@ static u16 read_srom_word(long ioaddr, int offset) for (i = 16; i > 0; i--) { outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr); udelay(5); - srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0); + srom_data = (srom_data << 1) | + ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0); outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); udelay(5); } @@ -1537,9 +1592,11 @@ static u8 dmfe_sense_speed(struct dmfe_board_info * db) if ( (phy_mode & 0x24) == 0x24 ) { if (db->chip_id == PCI_DM9132_ID) /* DM9132 */ - phy_mode = phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) & 0xf000; + phy_mode = phy_read(db->ioaddr, + db->phy_addr, 7, db->chip_id) & 0xf000; else /* DM9102/DM9102A */ - phy_mode = phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0xf000; + phy_mode = phy_read(db->ioaddr, + db->phy_addr, 17, db->chip_id) & 0xf000; /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ switch (phy_mode) { case 0x1000: db->op_mode = DMFE_10MHF; break; @@ -1576,8 +1633,11 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *db) /* DM9009 Chip: Phyxcer reg18 bit12=0 */ if (db->chip_id == PCI_DM9009_ID) { - phy_reg = phy_read(db->ioaddr, db->phy_addr, 18, db->chip_id) & ~0x1000; - phy_write(db->ioaddr, db->phy_addr, 18, phy_reg, db->chip_id); + phy_reg = phy_read(db->ioaddr, + db->phy_addr, 18, db->chip_id) & ~0x1000; + + phy_write(db->ioaddr, + db->phy_addr, 18, phy_reg, db->chip_id); } /* Phyxcer capability setting */ @@ -1650,10 +1710,12 @@ static void dmfe_process_mode(struct dmfe_board_info *db) case DMFE_100MHF: phy_reg = 0x2000; break; case DMFE_100MFD: phy_reg = 0x2100; break; } - phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); + phy_write(db->ioaddr, + db->phy_addr, 0, phy_reg, db->chip_id); if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) ) mdelay(20); - phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); + phy_write(db->ioaddr, + db->phy_addr, 0, phy_reg, db->chip_id); } } } @@ -1663,7 +1725,8 @@ static void dmfe_process_mode(struct dmfe_board_info *db) * Write a word to Phy register */ -static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id) +static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, + u16 phy_data, u32 chip_id) { u16 i; unsigned long ioaddr; @@ -1689,11 +1752,13 @@ static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data /* Send Phy address */ for (i = 0x10; i > 0; i = i >> 1) - phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); + phy_write_1bit(ioaddr, + phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); /* Send register address */ for (i = 0x10; i > 0; i = i >> 1) - phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); + phy_write_1bit(ioaddr, + offset & i ? PHY_DATA_1 : PHY_DATA_0); /* written trasnition */ phy_write_1bit(ioaddr, PHY_DATA_1); @@ -1701,7 +1766,8 @@ static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data /* Write a word data to PHY controller */ for ( i = 0x8000; i > 0; i >>= 1) - phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0); + phy_write_1bit(ioaddr, + phy_data & i ? PHY_DATA_1 : PHY_DATA_0); } } @@ -1738,11 +1804,13 @@ static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id) /* Send Phy address */ for (i = 0x10; i > 0; i = i >> 1) - phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); + phy_write_1bit(ioaddr, + phy_addr & i ? PHY_DATA_1 : PHY_DATA_0); /* Send register address */ for (i = 0x10; i > 0; i = i >> 1) - phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0); + phy_write_1bit(ioaddr, + offset & i ? PHY_DATA_1 : PHY_DATA_0); /* Skip transition state */ phy_read_1bit(ioaddr); @@ -1963,7 +2031,8 @@ static void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db) /* Check remote device status match our setting ot not */ if ( phy_reg != (db->HPNA_command & 0x0f00) ) { - phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id); + phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, + db->chip_id); db->HPNA_timer=8; } else db->HPNA_timer=600; /* Match, every 10 minutes, check */ @@ -2003,8 +2072,11 @@ module_param(HPNA_tx_cmd, byte, 0); module_param(HPNA_NoiseFloor, byte, 0); module_param(SF_mode, byte, 0); MODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)"); -MODULE_PARM_DESC(mode, "Davicom DM9xxx: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA"); -MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function (bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)"); +MODULE_PARM_DESC(mode, "Davicom DM9xxx: " + "Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA"); + +MODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function " + "(bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)"); /* Description: * when user used insmod to add module, system invoked init_module() diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 5a35354aa52..e3774a52237 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -67,7 +67,7 @@ const char * const medianame[32] = { /* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */ #if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \ - || defined(__sparc_) || defined(__ia64__) \ + || defined(__sparc__) || defined(__ia64__) \ || defined(__sh__) || defined(__mips__) static int rx_copybreak = 1518; #else diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 9781b16bb8b..0d91d094edd 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -746,8 +746,7 @@ typhoon_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { struct typhoon *tp = netdev_priv(dev); spin_lock_bh(&tp->state_lock); - if(tp->vlgrp) - tp->vlgrp->vlan_devices[vid] = NULL; + vlan_group_set_device(tp->vlgrp, vid, NULL); spin_unlock_bh(&tp->state_lock); } diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index a2fc2bbcf97..dab88b958d6 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -3598,17 +3598,20 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Move to next BD in the ring */ if (!(bd_status & T_W)) - ugeth->txBd[txQ] = bd + sizeof(struct qe_bd); + bd += sizeof(struct qe_bd); else - ugeth->txBd[txQ] = ugeth->p_tx_bd_ring[txQ]; + bd = ugeth->p_tx_bd_ring[txQ]; /* If the next BD still needs to be cleaned up, then the bds are full. We need to tell the kernel to stop sending us stuff. */ if (bd == ugeth->confBd[txQ]) { if (!netif_queue_stopped(dev)) netif_stop_queue(dev); + return NETDEV_TX_BUSY; } + ugeth->txBd[txQ] = bd; + if (ugeth->p_scheduler) { ugeth->cpucount[txQ]++; /* Indicate to QE that there are more Tx bds ready for @@ -3620,7 +3623,7 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&ugeth->lock); - return 0; + return NETDEV_TX_OK; } static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit) @@ -3722,7 +3725,7 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) /* Handle the transmitted buffer and release */ /* the BD to be used with the current frame */ - if ((bd = ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0)) + if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0)) break; ugeth->stats.tx_packets++; @@ -3741,10 +3744,12 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) /* Advance the confirmation BD pointer */ if (!(bd_status & T_W)) - ugeth->confBd[txQ] += sizeof(struct qe_bd); + bd += sizeof(struct qe_bd); else - ugeth->confBd[txQ] = ugeth->p_tx_bd_ring[txQ]; + bd = ugeth->p_tx_bd_ring[txQ]; + bd_status = in_be32((u32 *)bd); } + ugeth->confBd[txQ] = bd; return 0; } @@ -4199,9 +4204,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ugeth->ug_info = ug_info; ugeth->dev = dev; - mac_addr = get_property(np, "mac-address", NULL); - if (mac_addr == NULL) - mac_addr = get_property(np, "local-mac-address", NULL); + mac_addr = of_get_mac_address(np); if (mac_addr) memcpy(dev->dev_addr, mac_addr, 6); diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index ebbda1d8f54..f3a972e74e9 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -30,8 +30,8 @@ */ #define DRV_NAME "via-rhine" -#define DRV_VERSION "1.4.2" -#define DRV_RELDATE "Sept-11-2006" +#define DRV_VERSION "1.4.3" +#define DRV_RELDATE "2007-03-06" /* A few user-configurable values. @@ -105,6 +105,7 @@ static const int multicast_filter_limit = 32; #include <asm/io.h> #include <asm/irq.h> #include <asm/uaccess.h> +#include <linux/dmi.h> /* These identify the driver base version and may not be removed. */ static char version[] __devinitdata = @@ -1995,6 +1996,23 @@ static struct pci_driver rhine_driver = { .shutdown = rhine_shutdown, }; +static struct dmi_system_id __initdata rhine_dmi_table[] = { + { + .ident = "EPIA-M", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "Award Software International, Inc."), + DMI_MATCH(DMI_BIOS_VERSION, "6.00 PG"), + }, + }, + { + .ident = "KV7", + .matches = { + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"), + DMI_MATCH(DMI_BIOS_VERSION, "6.00 PG"), + }, + }, + { NULL } +}; static int __init rhine_init(void) { @@ -2002,6 +2020,16 @@ static int __init rhine_init(void) #ifdef MODULE printk(version); #endif + if (dmi_check_system(rhine_dmi_table)) { + /* these BIOSes fail at PXE boot if chip is in D3 */ + avoid_D3 = 1; + printk(KERN_WARNING "%s: Broken BIOS detected, avoid_D3 " + "enabled.\n", + DRV_NAME); + } + else if (avoid_D3) + printk(KERN_INFO "%s: avoid_D3 set.\n", DRV_NAME); + return pci_register_driver(&rhine_driver); } diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index e91b5a84a20..5b82e4fd0d7 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -94,7 +94,6 @@ #include <linux/device.h> #undef COSA_SLOW_IO /* for testing purposes only */ -#undef REALLY_SLOW_IO #include <asm/io.h> #include <asm/dma.h> diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 9040d7cf651..65ad2e24caf 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -38,7 +38,7 @@ #include <linux/hdlc.h> -static const char* version = "HDLC support module revision 1.20"; +static const char* version = "HDLC support module revision 1.21"; #undef DEBUG_LINK @@ -222,19 +222,31 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EINVAL; } +static void hdlc_setup_dev(struct net_device *dev) +{ + /* Re-init all variables changed by HDLC protocol drivers, + * including ether_setup() called from hdlc_raw_eth.c. + */ + dev->get_stats = hdlc_get_stats; + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + dev->mtu = HDLC_MAX_MTU; + dev->type = ARPHRD_RAWHDLC; + dev->hard_header_len = 16; + dev->addr_len = 0; + dev->hard_header = NULL; + dev->rebuild_header = NULL; + dev->set_mac_address = NULL; + dev->hard_header_cache = NULL; + dev->header_cache_update = NULL; + dev->change_mtu = hdlc_change_mtu; + dev->hard_header_parse = NULL; +} + static void hdlc_setup(struct net_device *dev) { hdlc_device *hdlc = dev_to_hdlc(dev); - dev->get_stats = hdlc_get_stats; - dev->change_mtu = hdlc_change_mtu; - dev->mtu = HDLC_MAX_MTU; - - dev->type = ARPHRD_RAWHDLC; - dev->hard_header_len = 16; - - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - + hdlc_setup_dev(dev); hdlc->carrier = 1; hdlc->open = 0; spin_lock_init(&hdlc->state_lock); @@ -294,6 +306,7 @@ void detach_hdlc_protocol(struct net_device *dev) } kfree(hdlc->state); hdlc->state = NULL; + hdlc_setup_dev(dev); } diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index b0bc5ddcf1b..c9664fd8a91 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -365,10 +365,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr) memcpy(&state(hdlc)->settings, &new_settings, size); dev->hard_start_xmit = hdlc->xmit; dev->hard_header = cisco_hard_header; - dev->hard_header_cache = NULL; dev->type = ARPHRD_CISCO; - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - dev->addr_len = 0; netif_dormant_on(dev); return 0; } diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index b45ab680d2d..c6c3c757d6f 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -1289,10 +1289,7 @@ static int fr_ioctl(struct net_device *dev, struct ifreq *ifr) memcpy(&state(hdlc)->settings, &new_settings, size); dev->hard_start_xmit = hdlc->xmit; - dev->hard_header = NULL; dev->type = ARPHRD_FRAD; - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - dev->addr_len = 0; return 0; case IF_PROTO_FR_ADD_PVC: diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index e9f717070fd..4591437dd2f 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -127,9 +127,7 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) if (result) return result; dev->hard_start_xmit = hdlc->xmit; - dev->hard_header = NULL; dev->type = ARPHRD_PPP; - dev->addr_len = 0; netif_dormant_off(dev); return 0; } diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c index fe3cae5c6b9..e23bc665626 100644 --- a/drivers/net/wan/hdlc_raw.c +++ b/drivers/net/wan/hdlc_raw.c @@ -88,10 +88,7 @@ static int raw_ioctl(struct net_device *dev, struct ifreq *ifr) return result; memcpy(hdlc->state, &new_settings, size); dev->hard_start_xmit = hdlc->xmit; - dev->hard_header = NULL; dev->type = ARPHRD_RAWHDLC; - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - dev->addr_len = 0; netif_dormant_off(dev); return 0; } diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c index e4bb9f8ad43..cd7b22f50ed 100644 --- a/drivers/net/wan/hdlc_x25.c +++ b/drivers/net/wan/hdlc_x25.c @@ -215,9 +215,7 @@ static int x25_ioctl(struct net_device *dev, struct ifreq *ifr) x25_rx, 0)) != 0) return result; dev->hard_start_xmit = x25_xmit; - dev->hard_header = NULL; dev->type = ARPHRD_X25; - dev->addr_len = 0; netif_dormant_off(dev); return 0; } diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 8dbcf83bb5f..8b4540bfc1b 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -407,7 +407,7 @@ static void z8530_tx(struct z8530_channel *c) while(c->txcount) { /* FIFO full ? */ if(!(read_zsreg(c, R0)&4)) - break; + return; c->txcount--; /* * Shovel out the byte diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 73c831a3b74..80cb88eb98c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1858,9 +1858,6 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id) spin_lock(&bcm->irq_lock); - assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); - assert(bcm->current_core->id == BCM43xx_COREID_80211); - reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) { /* irq not for us (shared irq) */ @@ -1871,6 +1868,9 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id) if (!reason) goto out; + assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); + assert(bcm->current_core->id == BCM43xx_COREID_80211); + bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON) & 0x0001DC00; bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) @@ -2733,8 +2733,9 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) * dangling pins on the second core. Be careful * and ignore these cores here. */ - if (bcm->pci_dev->device != 0x4324) { - dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n"); + if (1 /*bcm->pci_dev->device != 0x4324*/ ) { + /* TODO: A PHY */ + dprintk(KERN_INFO PFX "Ignoring additional 802.11a core.\n"); continue; } } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 3a5c9c2b215..cae89258a64 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -859,6 +859,11 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) bcm43xx_radio_write16(bcm, 0x005D, 0x0088); bcm43xx_radio_write16(bcm, 0x005E, 0x0088); bcm43xx_radio_write16(bcm, 0x007D, 0x0088); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET) + | 0x00000200)); } if (radio->revision == 8) { bcm43xx_radio_write16(bcm, 0x0051, 0x0000); @@ -941,7 +946,8 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0038, 0x0668); bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); if (radio->revision <= 5) - bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003); + bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) + & 0xFF80) | 0x0003); if (radio->revision <= 2) bcm43xx_radio_write16(bcm, 0x005D, 0x000D); @@ -958,7 +964,7 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0016, 0x0410); bcm43xx_phy_write(bcm, 0x0017, 0x0820); bcm43xx_phy_write(bcm, 0x0062, 0x0007); - (void) bcm43xx_radio_calibrationvalue(bcm); + bcm43xx_radio_init2050(bcm); bcm43xx_phy_lo_g_measure(bcm); if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { bcm43xx_calc_nrssi_slope(bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 7b665e2386a..d6d9413d7f2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -105,18 +105,24 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; u8 channel; + s8 expon; int freq; int err = -EINVAL; mutex_lock(&bcm->mutex); spin_lock_irqsave(&bcm->irq_lock, flags); - if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { + if ((data->freq.e == 0) && + (data->freq.m >= 0) && (data->freq.m <= 1000)) { channel = data->freq.m; freq = bcm43xx_channel_to_freq(bcm, channel); } else { - channel = bcm43xx_freq_to_channel(bcm, data->freq.m); freq = data->freq.m; + expon = 6 - data->freq.e; + while (--expon >= 0) /* scale down the frequency to MHz */ + freq /= 10; + assert(freq > 1000); + channel = bcm43xx_freq_to_channel(bcm, freq); } if (!ieee80211_is_valid_channel(bcm->ieee, channel)) goto out_unlock; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index c250f08c8dd..ce9230b2f63 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -26,7 +26,6 @@ * Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode * with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60) */ -#undef REALLY_SLOW_IO /* most systems can safely undef this */ #include <linux/delay.h> #include <linux/types.h> diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c index 07dc2b6d4e9..9bb4db552f3 100644 --- a/drivers/parisc/hppb.c +++ b/drivers/parisc/hppb.c @@ -10,10 +10,6 @@ ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** -** This Driver currently only supports the console (port 0) on the MUX. -** Additional work will be needed on this driver to enable the full -** functionality of the MUX. -** */ #include <linux/types.h> @@ -67,7 +63,7 @@ static int hppb_probe(struct parisc_device *dev) } card = card->next; } - printk(KERN_INFO "Found GeckoBoa at 0x%lx\n", dev->hpa.start); + printk(KERN_INFO "Found GeckoBoa at 0x%x\n", dev->hpa.start); card->hpa = dev->hpa.start; card->mmio_region.name = "HP-PB Bus"; @@ -78,16 +74,18 @@ static int hppb_probe(struct parisc_device *dev) status = ccio_request_resource(dev, &card->mmio_region); if(status < 0) { - printk(KERN_ERR "%s: failed to claim HP-PB bus space (%08lx, %08lx)\n", + printk(KERN_ERR "%s: failed to claim HP-PB bus space (%08x, %08x)\n", __FILE__, card->mmio_region.start, card->mmio_region.end); } return 0; } - static struct parisc_device_id hppb_tbl[] = { - { HPHW_BCPORT, HVERSION_REV_ANY_ID, 0x500, 0xc }, + { HPHW_BCPORT, HVERSION_REV_ANY_ID, 0x500, 0xc }, /* E25 and K */ + { HPHW_BCPORT, 0x0, 0x501, 0xc }, /* E35 */ + { HPHW_BCPORT, 0x0, 0x502, 0xc }, /* E45 */ + { HPHW_BCPORT, 0x0, 0x503, 0xc }, /* E55 */ { 0, } }; diff --git a/drivers/parisc/iosapic_private.h b/drivers/parisc/iosapic_private.h index 41e7ec2a44a..6e05e30a245 100644 --- a/drivers/parisc/iosapic_private.h +++ b/drivers/parisc/iosapic_private.h @@ -132,7 +132,7 @@ struct iosapic_irt { struct vector_info { struct iosapic_info *iosapic; /* I/O SAPIC this vector is on */ struct irt_entry *irte; /* IRT entry */ - u32 *eoi_addr; /* precalculate EOI reg address */ + u32 __iomem *eoi_addr; /* precalculate EOI reg address */ u32 eoi_data; /* IA64: ? PA: swapped txn_data */ int txn_irq; /* virtual IRQ number for processor */ ulong txn_addr; /* IA64: id_eid PA: partial HPA */ diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index ba6769934c7..21c4c299b3d 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -168,7 +168,8 @@ lba_dump_res(struct resource *r, int d) printk(KERN_DEBUG "(%p)", r->parent); for (i = d; i ; --i) printk(" "); - printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r, r->start, r->end, r->flags); + printk(KERN_DEBUG "%p [%lx,%lx]/%lx\n", r, + (long)r->start, (long)r->end, r->flags); lba_dump_res(r->child, d+2); lba_dump_res(r->sibling, d); } @@ -647,7 +648,7 @@ truncate_pat_collision(struct resource *root, struct resource *new) printk(KERN_WARNING "LBA: Truncating lmmio_space [%lx/%lx] " "to [%lx,%lx]\n", start, end, - new->start, new->end ); + (long)new->start, (long)new->end ); return 0; /* truncation successful */ } @@ -715,8 +716,8 @@ lba_fixup_bus(struct pci_bus *bus) printk("FAILED: lba_fixup_bus() request for " "elmmio_space [%lx/%lx]\n", - ldev->hba.elmmio_space.start, - ldev->hba.elmmio_space.end); + (long)ldev->hba.elmmio_space.start, + (long)ldev->hba.elmmio_space.end); /* lba_dump_res(&iomem_resource, 2); */ /* BUG(); */ @@ -738,15 +739,15 @@ lba_fixup_bus(struct pci_bus *bus) &(ldev->hba.lmmio_space))) { printk(KERN_WARNING "LBA: lmmio_space [%lx/%lx] duplicate!\n", - ldev->hba.lmmio_space.start, - ldev->hba.lmmio_space.end); + (long)ldev->hba.lmmio_space.start, + (long)ldev->hba.lmmio_space.end); } else { err = request_resource(&iomem_resource, &(ldev->hba.lmmio_space)); if (err < 0) { printk(KERN_ERR "FAILED: lba_fixup_bus() request for " "lmmio_space [%lx/%lx]\n", - ldev->hba.lmmio_space.start, - ldev->hba.lmmio_space.end); + (long)ldev->hba.lmmio_space.start, + (long)ldev->hba.lmmio_space.end); } else bus->resource[i++] = &(ldev->hba.lmmio_space); } @@ -758,8 +759,8 @@ lba_fixup_bus(struct pci_bus *bus) if (err < 0) { printk("FAILED: lba_fixup_bus() request for " "gmmio_space [%lx/%lx]\n", - ldev->hba.gmmio_space.start, - ldev->hba.gmmio_space.end); + (long)ldev->hba.gmmio_space.start, + (long)ldev->hba.gmmio_space.end); lba_dump_res(&iomem_resource, 2); BUG(); } @@ -980,7 +981,7 @@ LBA_PORT_IN(32, 0) #define LBA_PORT_OUT(size, mask) \ static void lba_pat_out##size (struct pci_hba_data *l, u16 addr, u##size val) \ { \ - void *where = (void *) PIOP_TO_GMMIO(LBA_DEV(l), addr); \ + void __iomem *where = PIOP_TO_GMMIO(LBA_DEV(l), addr); \ DBG_PORT("%s(0x%p, 0x%x, 0x%x)\n", __FUNCTION__, l, addr, val); \ WRITE_REG##size(val, where); \ /* flush the I/O down to the elroy at least */ \ @@ -1063,16 +1064,16 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) /* used to fix up pre-initialized MEM BARs */ if (!lba_dev->hba.lmmio_space.start) { sprintf(lba_dev->hba.lmmio_name, - "PCI%02lx LMMIO", - lba_dev->hba.bus_num.start); + "PCI%02x LMMIO", + (int)lba_dev->hba.bus_num.start); lba_dev->hba.lmmio_space_offset = p->start - io->start; r = &lba_dev->hba.lmmio_space; r->name = lba_dev->hba.lmmio_name; } else if (!lba_dev->hba.elmmio_space.start) { sprintf(lba_dev->hba.elmmio_name, - "PCI%02lx ELMMIO", - lba_dev->hba.bus_num.start); + "PCI%02x ELMMIO", + (int)lba_dev->hba.bus_num.start); r = &lba_dev->hba.elmmio_space; r->name = lba_dev->hba.elmmio_name; } else { @@ -1089,8 +1090,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) case PAT_GMMIO: /* MMIO space > 4GB phys addr; for 64-bit BAR */ - sprintf(lba_dev->hba.gmmio_name, "PCI%02lx GMMIO", - lba_dev->hba.bus_num.start); + sprintf(lba_dev->hba.gmmio_name, "PCI%02x GMMIO", + (int)lba_dev->hba.bus_num.start); r = &lba_dev->hba.gmmio_space; r->name = lba_dev->hba.gmmio_name; r->start = p->start; @@ -1112,8 +1113,8 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) */ lba_dev->iop_base = ioremap_nocache(p->start, 64 * 1024 * 1024); - sprintf(lba_dev->hba.io_name, "PCI%02lx Ports", - lba_dev->hba.bus_num.start); + sprintf(lba_dev->hba.io_name, "PCI%02x Ports", + (int)lba_dev->hba.bus_num.start); r = &lba_dev->hba.io_space; r->name = lba_dev->hba.io_name; r->start = HBA_PORT_BASE(lba_dev->hba.hba_num); @@ -1166,8 +1167,8 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) ** Legacy boxes but it's nice to see in /proc/iomem. */ r = &(lba_dev->hba.lmmio_space); - sprintf(lba_dev->hba.lmmio_name, "PCI%02lx LMMIO", - lba_dev->hba.bus_num.start); + sprintf(lba_dev->hba.lmmio_name, "PCI%02x LMMIO", + (int)lba_dev->hba.bus_num.start); r->name = lba_dev->hba.lmmio_name; #if 1 @@ -1275,8 +1276,8 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) ** an existing (but unused portion of) distributed range. */ r = &(lba_dev->hba.elmmio_space); - sprintf(lba_dev->hba.elmmio_name, "PCI%02lx ELMMIO", - lba_dev->hba.bus_num.start); + sprintf(lba_dev->hba.elmmio_name, "PCI%02x ELMMIO", + (int)lba_dev->hba.bus_num.start); r->name = lba_dev->hba.elmmio_name; #if 1 @@ -1297,8 +1298,8 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev) #endif r = &(lba_dev->hba.io_space); - sprintf(lba_dev->hba.io_name, "PCI%02lx Ports", - lba_dev->hba.bus_num.start); + sprintf(lba_dev->hba.io_name, "PCI%02x Ports", + (int)lba_dev->hba.bus_num.start); r->name = lba_dev->hba.io_name; r->flags = IORESOURCE_IO; r->start = READ_REG32(lba_dev->hba.base_addr + LBA_IOS_BASE) & ~1L; @@ -1406,13 +1407,20 @@ lba_hw_init(struct lba_device *d) return 0; } - +/* + * Unfortunately, when firmware numbers busses, it doesn't take into account + * Cardbus bridges. So we have to renumber the busses to suit ourselves. + * Elroy/Mercury don't actually know what bus number they're attached to; + * we use bus 0 to indicate the directly attached bus and any other bus + * number will be taken care of by the PCI-PCI bridge. + */ +static unsigned int lba_next_bus = 0; /* -** Determine if lba should claim this chip (return 0) or not (return 1). -** If so, initialize the chip and tell other partners in crime they -** have work to do. -*/ + * Determine if lba should claim this chip (return 0) or not (return 1). + * If so, initialize the chip and tell other partners in crime they + * have work to do. + */ static int __init lba_driver_probe(struct parisc_device *dev) { @@ -1440,7 +1448,7 @@ lba_driver_probe(struct parisc_device *dev) } printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n", - version, func_class & 0xf, dev->hpa.start); + version, func_class & 0xf, (long)dev->hpa.start); if (func_class < 2) { printk(KERN_WARNING "Can't support LBA older than " @@ -1470,17 +1478,16 @@ lba_driver_probe(struct parisc_device *dev) */ printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n", IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major, - minor, func_class, dev->hpa.start); + minor, func_class, (long)dev->hpa.start); cfg_ops = &mercury_cfg_ops; } else { - printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start); + printk(KERN_ERR "Unknown LBA found at 0x%lx\n", + (long)dev->hpa.start); return -ENODEV; } - /* - ** Tell I/O SAPIC driver we have a IRQ handler/region. - */ + /* Tell I/O SAPIC driver we have a IRQ handler/region. */ tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE); /* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't @@ -1529,16 +1536,17 @@ lba_driver_probe(struct parisc_device *dev) lba_legacy_resources(dev, lba_dev); } - /* - ** Tell PCI support another PCI bus was found. - ** Walks PCI bus for us too. - */ + if (lba_dev->hba.bus_num.start < lba_next_bus) + lba_dev->hba.bus_num.start = lba_next_bus; + dev->dev.platform_data = lba_dev; lba_bus = lba_dev->hba.hba_bus = pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start, cfg_ops, NULL); - if (lba_bus) + if (lba_bus) { + lba_next_bus = lba_bus->subordinate + 1; pci_bus_add_devices(lba_bus); + } /* This is in lieu of calling pci_assign_unassigned_resources() */ if (is_pdc_pat()) { diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index 9a731c101d1..d190c05d87e 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -66,8 +66,8 @@ static char lcd_text_default[32] __read_mostly; static struct workqueue_struct *led_wq; -static void led_work_func(void *); -static DECLARE_WORK(led_task, led_work_func, NULL); +static void led_work_func(struct work_struct *); +static DECLARE_DELAYED_WORK(led_task, led_work_func); #if 0 #define DPRINTK(x) printk x @@ -136,7 +136,7 @@ static int start_task(void) /* Create the work queue and queue the LED task */ led_wq = create_singlethread_workqueue("led_wq"); - queue_work(led_wq, &led_task); + queue_delayed_work(led_wq, &led_task, 0); return 0; } @@ -441,7 +441,7 @@ static __inline__ int led_get_diskio_activity(void) #define LED_UPDATE_INTERVAL (1 + (HZ*19/1000)) -static void led_work_func (void *unused) +static void led_work_func (struct work_struct *unused) { static unsigned long last_jiffies; static unsigned long count_HZ; /* counter in range 0..HZ */ @@ -588,7 +588,7 @@ int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long d /* Ensure the work is queued */ if (led_wq) { - queue_work(led_wq, &led_task); + queue_delayed_work(led_wq, &led_task, 0); } return 0; @@ -629,7 +629,7 @@ void __init register_led_regions(void) ** avoid a race condition while writing the CMD/DATA register pair. ** */ -int lcd_print( char *str ) +int lcd_print( const char *str ) { int i; @@ -658,7 +658,7 @@ int lcd_print( char *str ) /* re-queue the work */ if (led_wq) { - queue_work(led_wq, &led_task); + queue_delayed_work(led_wq, &led_task, 0); } return lcd_info.lcd_width; diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c index 97e9dc066f9..6dedbdef710 100644 --- a/drivers/parisc/power.c +++ b/drivers/parisc/power.c @@ -2,7 +2,7 @@ * linux/drivers/parisc/power.c * HP PARISC soft power switch support driver * - * Copyright (c) 2001-2005 Helge Deller <deller@gmx.de> + * Copyright (c) 2001-2007 Helge Deller <deller@gmx.de> * All rights reserved. * * @@ -29,7 +29,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * * - * * HINT: * Support of the soft power switch button may be enabled or disabled at * runtime through the "/proc/sys/kernel/power" procfs entry. @@ -38,34 +37,28 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/string.h> #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/workqueue.h> +#include <linux/kthread.h> #include <asm/pdc.h> #include <asm/io.h> #include <asm/led.h> -#include <asm/uaccess.h> +#define DRIVER_NAME "powersw" +#define KTHREAD_NAME "kpowerswd" -#ifdef DEBUG -# define DPRINTK(x...) printk(x) -#else -# define DPRINTK(x...) -#endif - - -/* filename in /proc which can be used to enable/disable the power switch */ -#define SYSCTL_FILENAME "sys/kernel/power" +/* how often should the power button be polled ? */ +#define POWERSWITCH_POLL_PER_SEC 2 +/* how long does the power button needs to be down until we react ? */ +#define POWERSWITCH_DOWN_SEC 2 +/* assembly code to access special registers */ +/* taken from PCXL ERS page 82 */ #define DIAG_CODE(code) (0x14000000 + ((code)<<5)) -/* this will go to processor.h or any other place... */ -/* taken from PCXL ERS page 82 */ #define MFCPU_X(rDiagReg, t_ch, t_th, code) \ (DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) ) @@ -76,111 +69,95 @@ #define __getDIAG(dr) ( { \ register unsigned long __res asm("r28");\ __asm__ __volatile__ ( \ - ".word %1\n nop\n" : "=&r" (__res) : "i" (MFCPU_T(dr,28)) \ + ".word %1" : "=&r" (__res) : "i" (MFCPU_T(dr,28) ) \ ); \ __res; \ } ) - -static void deferred_poweroff(void *dummy) -{ - if (kill_cad_pid(SIGINT, 1)) { - /* just in case killing init process failed */ - machine_power_off(); - } -} - -/* - * This function gets called from interrupt context. - * As it's called within an interrupt, it wouldn't sync if we don't - * use schedule_work(). - */ - -static DECLARE_WORK(poweroff_work, deferred_poweroff, NULL); - -static void poweroff(void) -{ - static int powering_off __read_mostly; - - if (powering_off) - return; - - powering_off++; - schedule_work(&poweroff_work); -} - - -/* local time-counter for shutdown */ +/* local shutdown counter */ static int shutdown_timer __read_mostly; /* check, give feedback and start shutdown after one second */ static void process_shutdown(void) { if (shutdown_timer == 0) - DPRINTK(KERN_INFO "Shutdown requested...\n"); + printk(KERN_ALERT KTHREAD_NAME ": Shutdown requested...\n"); shutdown_timer++; /* wait until the button was pressed for 1 second */ - if (shutdown_timer == HZ) { -#if defined (DEBUG) || defined(CONFIG_CHASSIS_LCD_LED) - static char msg[] = "Shutting down..."; -#endif - DPRINTK(KERN_INFO "%s\n", msg); + if (shutdown_timer == (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC)) { + static const char msg[] = "Shutting down..."; + printk(KERN_INFO KTHREAD_NAME ": %s\n", msg); lcd_print(msg); - poweroff(); + + /* send kill signal */ + if (kill_cad_pid(SIGINT, 1)) { + /* just in case killing init process failed */ + if (pm_power_off) + pm_power_off(); + } } } -/* main power switch tasklet struct (scheduled from time.c) */ -DECLARE_TASKLET_DISABLED(power_tasklet, NULL, 0); +/* main power switch task struct */ +static struct task_struct *power_task; + +/* filename in /proc which can be used to enable/disable the power switch */ +#define SYSCTL_FILENAME "sys/kernel/power" /* soft power switch enabled/disabled */ int pwrsw_enabled __read_mostly = 1; -/* - * On gecko style machines (e.g. 712/xx and 715/xx) - * the power switch status is stored in Bit 0 ("the highest bit") - * of CPU diagnose register 25. - * - */ -static void gecko_tasklet_func(unsigned long unused) +/* main kernel thread worker. It polls the button state */ +static int kpowerswd(void *param) { - if (unlikely(!pwrsw_enabled)) - return; - - if (__getDIAG(25) & 0x80000000) { - /* power switch button not pressed or released again */ - /* Warning: Some machines do never reset this DIAG flag! */ - shutdown_timer = 0; - } else { - process_shutdown(); - } -} - + __set_current_state(TASK_RUNNING); + + do { + int button_not_pressed; + unsigned long soft_power_reg = (unsigned long) param; + + schedule_timeout_interruptible(pwrsw_enabled ? HZ : HZ/POWERSWITCH_POLL_PER_SEC); + __set_current_state(TASK_RUNNING); + + if (unlikely(!pwrsw_enabled)) + continue; + + if (soft_power_reg) { + /* + * Non-Gecko-style machines: + * Check the power switch status which is read from the + * real I/O location at soft_power_reg. + * Bit 31 ("the lowest bit) is the status of the power switch. + * This bit is "1" if the button is NOT pressed. + */ + button_not_pressed = (gsc_readl(soft_power_reg) & 0x1); + } else { + /* + * On gecko style machines (e.g. 712/xx and 715/xx) + * the power switch status is stored in Bit 0 ("the highest bit") + * of CPU diagnose register 25. + * Warning: Some machines never reset the DIAG flag, even if + * the button has been released again. + */ + button_not_pressed = (__getDIAG(25) & 0x80000000); + } + + if (likely(button_not_pressed)) { + if (unlikely(shutdown_timer && /* avoid writing if not necessary */ + shutdown_timer < (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC))) { + shutdown_timer = 0; + printk(KERN_INFO KTHREAD_NAME ": Shutdown request aborted.\n"); + } + } else + process_shutdown(); + + + } while (!kthread_should_stop()); - -/* - * Check the power switch status which is read from the - * real I/O location at soft_power_reg. - * Bit 31 ("the lowest bit) is the status of the power switch. - */ - -static void polling_tasklet_func(unsigned long soft_power_reg) -{ - unsigned long current_status; - - if (unlikely(!pwrsw_enabled)) - return; - - current_status = gsc_readl(soft_power_reg); - if (current_status & 0x1) { - /* power switch button not pressed */ - shutdown_timer = 0; - } else { - process_shutdown(); - } + return 0; } @@ -220,7 +197,7 @@ static struct notifier_block parisc_panic_block = { static int __init power_init(void) { unsigned long ret; - unsigned long soft_power_reg = 0; + unsigned long soft_power_reg; #if 0 request_irq( IRQ_FROM_REGION(CPU_IRQ_REGION)+2, &powerfail_interrupt, @@ -235,44 +212,44 @@ static int __init power_init(void) soft_power_reg = -1UL; switch (soft_power_reg) { - case 0: printk(KERN_INFO "Gecko-style soft power switch enabled.\n"); - power_tasklet.func = gecko_tasklet_func; + case 0: printk(KERN_INFO DRIVER_NAME ": Gecko-style soft power switch enabled.\n"); break; - case -1UL: printk(KERN_INFO "Soft power switch support not available.\n"); + case -1UL: printk(KERN_INFO DRIVER_NAME ": Soft power switch support not available.\n"); return -ENODEV; - default: printk(KERN_INFO "Soft power switch enabled, polling @ 0x%08lx.\n", + default: printk(KERN_INFO DRIVER_NAME ": Soft power switch at 0x%08lx enabled.\n", soft_power_reg); - power_tasklet.data = soft_power_reg; - power_tasklet.func = polling_tasklet_func; + } + + power_task = kthread_run(kpowerswd, (void*)soft_power_reg, KTHREAD_NAME); + if (IS_ERR(power_task)) { + printk(KERN_ERR DRIVER_NAME ": thread creation failed. Driver not loaded.\n"); + pdc_soft_power_button(0); + return -EIO; } /* Register a call for panic conditions. */ atomic_notifier_chain_register(&panic_notifier_list, &parisc_panic_block); - tasklet_enable(&power_tasklet); - return 0; } static void __exit power_exit(void) { - if (!power_tasklet.func) - return; + kthread_stop(power_task); - tasklet_disable(&power_tasklet); atomic_notifier_chain_unregister(&panic_notifier_list, &parisc_panic_block); - power_tasklet.func = NULL; + pdc_soft_power_button(0); } -module_init(power_init); +arch_initcall(power_init); module_exit(power_exit); -MODULE_AUTHOR("Helge Deller"); +MODULE_AUTHOR("Helge Deller <deller@gmx.de>"); MODULE_DESCRIPTION("Soft power switch driver"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 76a29dadd51..322957ac2ad 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -109,7 +109,7 @@ static unsigned long piranha_bad_128k = 0; #ifdef SBA_AGP_SUPPORT static int sba_reserve_agpgart = 1; -module_param(sba_reserve_agpgart, int, 1); +module_param(sba_reserve_agpgart, int, 0444); MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART"); #endif @@ -846,7 +846,7 @@ static void *sba_alloc_consistent(struct device *hwdev, size_t size, if (!hwdev) { /* only support PCI */ *dma_handle = 0; - return 0; + return NULL; } ret = (void *) __get_free_pages(gfp, get_order(size)); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 68555c11f55..01869b1782e 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -38,6 +38,36 @@ static int msi_cache_init(void) return 0; } +static void msi_set_enable(struct pci_dev *dev, int enable) +{ + int pos; + u16 control; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (pos) { + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); + control &= ~PCI_MSI_FLAGS_ENABLE; + if (enable) + control |= PCI_MSI_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); + } +} + +static void msix_set_enable(struct pci_dev *dev, int enable) +{ + int pos; + u16 control; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (pos) { + pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); + control &= ~PCI_MSIX_FLAGS_ENABLE; + if (enable) + control |= PCI_MSIX_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); + } +} + static void msi_set_mask_bit(unsigned int irq, int flag) { struct msi_desc *entry; @@ -55,6 +85,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag) mask_bits &= ~(1); mask_bits |= flag; pci_write_config_dword(entry->dev, pos, mask_bits); + } else { + msi_set_enable(entry->dev, !flag); } break; case PCI_CAP_ID_MSIX: @@ -192,44 +224,6 @@ static struct msi_desc* alloc_msi_entry(void) return entry; } -static void enable_msi_mode(struct pci_dev *dev, int pos, int type) -{ - u16 control; - - pci_read_config_word(dev, msi_control_reg(pos), &control); - if (type == PCI_CAP_ID_MSI) { - /* Set enabled bits to single MSI & enable MSI_enable bit */ - msi_enable(control, 1); - pci_write_config_word(dev, msi_control_reg(pos), control); - dev->msi_enabled = 1; - } else { - msix_enable(control); - pci_write_config_word(dev, msi_control_reg(pos), control); - dev->msix_enabled = 1; - } - - pci_intx(dev, 0); /* disable intx */ -} - -void disable_msi_mode(struct pci_dev *dev, int pos, int type) -{ - u16 control; - - pci_read_config_word(dev, msi_control_reg(pos), &control); - if (type == PCI_CAP_ID_MSI) { - /* Set enabled bits to single MSI & enable MSI_enable bit */ - msi_disable(control); - pci_write_config_word(dev, msi_control_reg(pos), control); - dev->msi_enabled = 0; - } else { - msix_disable(control); - pci_write_config_word(dev, msi_control_reg(pos), control); - dev->msix_enabled = 0; - } - - pci_intx(dev, 1); /* enable intx */ -} - #ifdef CONFIG_PM static int __pci_save_msi_state(struct pci_dev *dev) { @@ -238,12 +232,11 @@ static int __pci_save_msi_state(struct pci_dev *dev) struct pci_cap_saved_state *save_state; u32 *cap; - pos = pci_find_capability(dev, PCI_CAP_ID_MSI); - if (pos <= 0 || dev->no_msi) + if (!dev->msi_enabled) return 0; - pci_read_config_word(dev, msi_control_reg(pos), &control); - if (!(control & PCI_MSI_FLAGS_ENABLE)) + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (pos <= 0) return 0; save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5, @@ -276,13 +269,18 @@ static void __pci_restore_msi_state(struct pci_dev *dev) struct pci_cap_saved_state *save_state; u32 *cap; + if (!dev->msi_enabled) + return; + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI); pos = pci_find_capability(dev, PCI_CAP_ID_MSI); if (!save_state || pos <= 0) return; cap = &save_state->data[0]; + pci_intx(dev, 0); /* disable intx */ control = cap[i++] >> 16; + msi_set_enable(dev, 0); pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]); if (control & PCI_MSI_FLAGS_64BIT) { pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]); @@ -292,7 +290,6 @@ static void __pci_restore_msi_state(struct pci_dev *dev) if (control & PCI_MSI_FLAGS_MASKBIT) pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]); pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); - enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); pci_remove_saved_cap(save_state); kfree(save_state); } @@ -308,13 +305,11 @@ static int __pci_save_msix_state(struct pci_dev *dev) return 0; pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos <= 0 || dev->no_msi) + if (pos <= 0) return 0; /* save the capability */ pci_read_config_word(dev, msi_control_reg(pos), &control); - if (!(control & PCI_MSIX_FLAGS_ENABLE)) - return 0; save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16), GFP_KERNEL); if (!save_state) { @@ -376,6 +371,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev) return; /* route the table */ + pci_intx(dev, 0); /* disable intx */ + msix_set_enable(dev, 0); irq = head = dev->first_msi_irq; while (head != tail) { entry = get_irq_msi(irq); @@ -386,7 +383,6 @@ static void __pci_restore_msix_state(struct pci_dev *dev) } pci_write_config_word(dev, msi_control_reg(pos), save); - enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); } void pci_restore_msi_state(struct pci_dev *dev) @@ -411,6 +407,8 @@ static int msi_capability_init(struct pci_dev *dev) int pos, irq; u16 control; + msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); pci_read_config_word(dev, msi_control_reg(pos), &control); /* MSI Entry Initialization */ @@ -454,7 +452,9 @@ static int msi_capability_init(struct pci_dev *dev) set_irq_msi(irq, entry); /* Set MSI enabled bits */ - enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + pci_intx(dev, 0); /* disable intx */ + msi_set_enable(dev, 1); + dev->msi_enabled = 1; dev->irq = irq; return 0; @@ -481,6 +481,8 @@ static int msix_capability_init(struct pci_dev *dev, u8 bir; void __iomem *base; + msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */ + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); /* Request & Map MSI-X table region */ pci_read_config_word(dev, msi_control_reg(pos), &control); @@ -549,7 +551,9 @@ static int msix_capability_init(struct pci_dev *dev, } dev->first_msi_irq = entries[0].vector; /* Set MSI-X enabled bits */ - enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); + pci_intx(dev, 0); /* disable intx */ + msix_set_enable(dev, 1); + dev->msix_enabled = 1; return 0; } @@ -611,12 +615,11 @@ int pci_enable_msi(struct pci_dev* dev) WARN_ON(!!dev->msi_enabled); /* Check whether driver already requested for MSI-X irqs */ - pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (pos > 0 && dev->msix_enabled) { - printk(KERN_INFO "PCI: %s: Can't enable MSI. " - "Device already has MSI-X enabled\n", - pci_name(dev)); - return -EINVAL; + if (dev->msix_enabled) { + printk(KERN_INFO "PCI: %s: Can't enable MSI. " + "Device already has MSI-X enabled\n", + pci_name(dev)); + return -EINVAL; } status = msi_capability_init(dev); return status; @@ -625,8 +628,7 @@ int pci_enable_msi(struct pci_dev* dev) void pci_disable_msi(struct pci_dev* dev) { struct msi_desc *entry; - int pos, default_irq; - u16 control; + int default_irq; if (!pci_msi_enable) return; @@ -636,16 +638,9 @@ void pci_disable_msi(struct pci_dev* dev) if (!dev->msi_enabled) return; - pos = pci_find_capability(dev, PCI_CAP_ID_MSI); - if (!pos) - return; - - pci_read_config_word(dev, msi_control_reg(pos), &control); - if (!(control & PCI_MSI_FLAGS_ENABLE)) - return; - - - disable_msi_mode(dev, pos, PCI_CAP_ID_MSI); + msi_set_enable(dev, 0); + pci_intx(dev, 1); /* enable intx */ + dev->msi_enabled = 0; entry = get_irq_msi(dev->first_msi_irq); if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { @@ -746,8 +741,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) WARN_ON(!!dev->msix_enabled); /* Check whether driver already requested for MSI irq */ - if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && - dev->msi_enabled) { + if (dev->msi_enabled) { printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " "Device already has an MSI irq assigned\n", pci_name(dev)); @@ -760,8 +754,6 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) void pci_disable_msix(struct pci_dev* dev) { int irq, head, tail = 0, warning = 0; - int pos; - u16 control; if (!pci_msi_enable) return; @@ -771,15 +763,9 @@ void pci_disable_msix(struct pci_dev* dev) if (!dev->msix_enabled) return; - pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); - if (!pos) - return; - - pci_read_config_word(dev, msi_control_reg(pos), &control); - if (!(control & PCI_MSIX_FLAGS_ENABLE)) - return; - - disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); + msix_set_enable(dev, 0); + pci_intx(dev, 1); /* enable intx */ + dev->msix_enabled = 0; irq = head = dev->first_msi_irq; while (head != tail) { diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1e74e1ee8bd..df495300ce3 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -881,13 +881,6 @@ pci_disable_device(struct pci_dev *dev) if (atomic_sub_return(1, &dev->enable_cnt) != 0) return; - if (dev->msi_enabled) - disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), - PCI_CAP_ID_MSI); - if (dev->msix_enabled) - disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), - PCI_CAP_ID_MSIX); - pci_read_config_word(dev, PCI_COMMAND, &pci_command); if (pci_command & PCI_COMMAND_MASTER) { pci_command &= ~PCI_COMMAND_MASTER; @@ -1277,6 +1270,33 @@ pci_intx(struct pci_dev *pdev, int enable) } } +/** + * pci_msi_off - disables any msi or msix capabilities + * @pdev: the PCI device to operate on + * + * If you want to use msi see pci_enable_msi and friends. + * This is a lower level primitive that allows us to disable + * msi operation at the device level. + */ +void pci_msi_off(struct pci_dev *dev) +{ + int pos; + u16 control; + + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (pos) { + pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); + control &= ~PCI_MSI_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); + } + pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); + if (pos) { + pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control); + control &= ~PCI_MSIX_FLAGS_ENABLE; + pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control); + } +} + #ifndef HAVE_ARCH_PCI_SET_DMA_MASK /* * These can be overridden by arch-specific implementations diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index a4f2d580625..ae7a975995a 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -46,10 +46,8 @@ extern struct rw_semaphore pci_bus_sem; extern unsigned int pci_pm_d3_delay; #ifdef CONFIG_PCI_MSI -void disable_msi_mode(struct pci_dev *dev, int pos, int type); void pci_no_msi(void); #else -static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { } static inline void pci_no_msi(void) { } #endif diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2fe1d690eb1..a4a96826d9e 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -682,7 +682,34 @@ static void pci_read_irq(struct pci_dev *dev) dev->irq = irq; } -#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) +static void change_legacy_io_resource(struct pci_dev * dev, unsigned index, + unsigned start, unsigned end) +{ + unsigned base = start & PCI_BASE_ADDRESS_IO_MASK; + unsigned len = (end | ~PCI_BASE_ADDRESS_IO_MASK) - base + 1; + + /* + * Some X versions get confused when the BARs reported through + * /sys or /proc differ from those seen in config space, thus + * try to update the config space values, too. + */ + if (!(pci_resource_flags(dev, index) & IORESOURCE_IO)) + printk(KERN_WARNING "%s: cannot adjust BAR%u (not I/O)\n", + pci_name(dev), index); + else if (pci_resource_len(dev, index) != len) + printk(KERN_WARNING "%s: cannot adjust BAR%u (size %04X)\n", + pci_name(dev), index, (unsigned)pci_resource_len(dev, index)); + else { + printk(KERN_INFO "%s: trying to change BAR%u from %04X to %04X\n", + pci_name(dev), index, + (unsigned)pci_resource_start(dev, index), base); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + index * 4, base); + } + pci_resource_start(dev, index) = start; + pci_resource_end(dev, index) = end; + pci_resource_flags(dev, index) = + IORESOURCE_IO | IORESOURCE_PCI_FIXED | PCI_BASE_ADDRESS_SPACE_IO; +} /** * pci_setup_device - fill in class and map information of a device @@ -735,20 +762,12 @@ static int pci_setup_device(struct pci_dev * dev) u8 progif; pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); if ((progif & 1) == 0) { - dev->resource[0].start = 0x1F0; - dev->resource[0].end = 0x1F7; - dev->resource[0].flags = LEGACY_IO_RESOURCE; - dev->resource[1].start = 0x3F6; - dev->resource[1].end = 0x3F6; - dev->resource[1].flags = LEGACY_IO_RESOURCE; + change_legacy_io_resource(dev, 0, 0x1F0, 0x1F7); + change_legacy_io_resource(dev, 1, 0x3F6, 0x3F6); } if ((progif & 4) == 0) { - dev->resource[2].start = 0x170; - dev->resource[2].end = 0x177; - dev->resource[2].flags = LEGACY_IO_RESOURCE; - dev->resource[3].start = 0x376; - dev->resource[3].end = 0x376; - dev->resource[3].flags = LEGACY_IO_RESOURCE; + change_legacy_io_resource(dev, 2, 0x170, 0x177); + change_legacy_io_resource(dev, 3, 0x376, 0x376); } } break; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 1e6eda25c0d..7f94fc098cd 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1218,45 +1218,68 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_a * do this early on to make the additional device appear during * the PCI scanning. */ - -static void quirk_jmicron_dualfn(struct pci_dev *pdev) +static void quirk_jmicron_ata(struct pci_dev *pdev) { - u32 conf; + u32 conf1, conf5, class; u8 hdr; /* Only poke fn 0 */ if (PCI_FUNC(pdev->devfn)) return; - switch(pdev->device) { - case PCI_DEVICE_ID_JMICRON_JMB365: - case PCI_DEVICE_ID_JMICRON_JMB366: - /* Redirect IDE second PATA port to the right spot */ - pci_read_config_dword(pdev, 0x80, &conf); - conf |= (1 << 24); - /* Fall through */ - pci_write_config_dword(pdev, 0x80, conf); - case PCI_DEVICE_ID_JMICRON_JMB361: - case PCI_DEVICE_ID_JMICRON_JMB363: - pci_read_config_dword(pdev, 0x40, &conf); - /* Enable dual function mode, AHCI on fn 0, IDE fn1 */ - /* Set the class codes correctly and then direct IDE 0 */ - conf &= ~0x000FF200; /* Clear bit 9 and 12-19 */ - conf |= 0x00C2A102; /* Set 1, 8, 13, 15, 17, 22, 23 */ - pci_write_config_dword(pdev, 0x40, conf); - - /* Reconfigure so that the PCI scanner discovers the - device is now multifunction */ - - pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr); - pdev->hdr_type = hdr & 0x7f; - pdev->multifunction = !!(hdr & 0x80); + pci_read_config_dword(pdev, 0x40, &conf1); + pci_read_config_dword(pdev, 0x80, &conf5); - break; + conf1 &= ~0x00CFF302; /* Clear bit 1, 8, 9, 12-19, 22, 23 */ + conf5 &= ~(1 << 24); /* Clear bit 24 */ + + switch (pdev->device) { + case PCI_DEVICE_ID_JMICRON_JMB360: + /* The controller should be in single function ahci mode */ + conf1 |= 0x0002A100; /* Set 8, 13, 15, 17 */ + break; + + case PCI_DEVICE_ID_JMICRON_JMB365: + case PCI_DEVICE_ID_JMICRON_JMB366: + /* Redirect IDE second PATA port to the right spot */ + conf5 |= (1 << 24); + /* Fall through */ + case PCI_DEVICE_ID_JMICRON_JMB361: + case PCI_DEVICE_ID_JMICRON_JMB363: + /* Enable dual function mode, AHCI on fn 0, IDE fn1 */ + /* Set the class codes correctly and then direct IDE 0 */ + conf1 |= 0x00C2A102; /* Set 1, 8, 13, 15, 17, 22, 23 */ + break; + + case PCI_DEVICE_ID_JMICRON_JMB368: + /* The controller should be in single function IDE mode */ + conf1 |= 0x00C00000; /* Set 22, 23 */ + break; } -} -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn); -DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn); + + pci_write_config_dword(pdev, 0x40, conf1); + pci_write_config_dword(pdev, 0x80, conf5); + + /* Update pdev accordingly */ + pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr); + pdev->hdr_type = hdr & 0x7f; + pdev->multifunction = !!(hdr & 0x80); + + pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class); + pdev->class = class >> 8; +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata); #endif @@ -1415,8 +1438,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quir */ static void __devinit quirk_pcie_pxh(struct pci_dev *dev) { - disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI), - PCI_CAP_ID_MSI); + pci_msi_off(dev); + dev->no_msi = 1; printk(KERN_WARNING "PCI: PXH quirk detected, " diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index caca0dc9d30..f2e810f53c8 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c @@ -907,7 +907,7 @@ static int __init init_hs(void) for (i=0; i<HS_MAX_SOCKETS; i++) { unsigned int ret; - hs_sockets[i].socket.dev.dev = &hd64465_device.dev; + hs_sockets[i].socket.dev.parent = &hd64465_device.dev; hs_sockets[i].number = i; ret = pcmcia_register_socket(&hs_sockets[i].socket); if (ret && i) diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index e4a94108aab..91da15b5a81 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c @@ -760,7 +760,7 @@ static int __init init_m32r_pcc(void) /* Set up interrupt handler(s) */ for (i = 0 ; i < pcc_sockets ; i++) { - socket[i].socket.dev.dev = &pcc_device.dev; + socket[i].socket.dev.parent = &pcc_device.dev; socket[i].socket.ops = &pcc_operations; socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.owner = THIS_MODULE; diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index d059c919617..9721ed7bf50 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c @@ -1321,7 +1321,7 @@ static int __init m8xx_init(void) socket[i].socket.ops = &m8xx_services; socket[i].socket.resource_ops = &pccard_iodyn_ops; socket[i].socket.cb_dev = NULL; - socket[i].socket.dev.dev = &m8xx_device.dev; + socket[i].socket.dev.parent = &m8xx_device.dev; } for (i = 0; i < PCMCIA_SOCKETS_NO; i++) diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c index 76f7cbc62a8..d77f75129f8 100644 --- a/drivers/pcmcia/omap_cf.c +++ b/drivers/pcmcia/omap_cf.c @@ -291,7 +291,7 @@ static int __devinit omap_cf_probe(struct device *dev) omap_cf_present() ? "present" : "(not present)"); cf->socket.owner = THIS_MODULE; - cf->socket.dev.dev = dev; + cf->socket.dev.parent = dev; cf->socket.ops = &omap_cf_ops; cf->socket.resource_ops = &pccard_static_ops; cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 81dfc2cac2b..ce2226273aa 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -232,7 +232,7 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num, unsigned long align, struct pcmcia_socket *s) { struct resource *res = make_resource(0, num, IORESOURCE_IO, - s->dev.class_id); + s->dev.bus_id); struct pcmcia_align_data data; unsigned long min = base; int ret; diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 206e26c9180..eee2f1cb213 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -596,7 +596,7 @@ static int __devinit vrc4171_add_sockets(void) } sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot); - socket->pcmcia_socket.dev.dev = &vrc4171_card_device.dev; + socket->pcmcia_socket.dev.parent = &vrc4171_card_device.dev; socket->pcmcia_socket.ops = &vrc4171_pccard_operations; socket->pcmcia_socket.owner = THIS_MODULE; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index deef29646e0..95826b92ca4 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -207,10 +207,12 @@ config RTC_DRV_PCF8563 config RTC_DRV_PCF8583 tristate "Philips PCF8583" - depends on RTC_CLASS && I2C + depends on RTC_CLASS && I2C && ARCH_RPC help - If you say yes here you get support for the - Philips PCF8583 RTC chip. + If you say yes here you get support for the Philips PCF8583 + RTC chip found on Acorn RiscPCs. This driver supports the + platform specific method of retrieving the current year from + the RTC's SRAM. This driver can also be built as a module. If so, the module will be called rtc-pcf8583. diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 7a0d8ee2de9..04aaa634723 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -113,10 +113,16 @@ EXPORT_SYMBOL_GPL(rtc_device_register); */ void rtc_device_unregister(struct rtc_device *rtc) { - mutex_lock(&rtc->ops_lock); - rtc->ops = NULL; - mutex_unlock(&rtc->ops_lock); - class_device_unregister(&rtc->class_dev); + if (class_device_get(&rtc->class_dev) != NULL) { + mutex_lock(&rtc->ops_lock); + /* remove innards of this RTC, then disable it, before + * letting any rtc_class_open() users access it again + */ + class_device_unregister(&rtc->class_dev); + rtc->ops = NULL; + mutex_unlock(&rtc->ops_lock); + class_device_put(&rtc->class_dev); + } } EXPORT_SYMBOL_GPL(rtc_device_unregister); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 6f11f6dfdd9..ef40df0f169 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -179,7 +179,7 @@ struct class_device *rtc_class_open(char *name) down(&rtc_class->sem); list_for_each_entry(class_dev_tmp, &rtc_class->children, node) { if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) { - class_dev = class_dev_tmp; + class_dev = class_device_get(class_dev_tmp); break; } } @@ -197,6 +197,7 @@ EXPORT_SYMBOL_GPL(rtc_class_open); void rtc_class_close(struct class_device *class_dev) { module_put(to_rtc_device(class_dev)->owner); + class_device_put(class_dev); } EXPORT_SYMBOL_GPL(rtc_class_close); diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 5875ebb8c79..d48b0337458 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -40,7 +40,7 @@ struct pcf8583 { #define CTRL_ALARM 0x02 #define CTRL_TIMER 0x01 -static unsigned short normal_i2c[] = { I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x50, I2C_CLIENT_END }; /* Module parameters */ I2C_CLIENT_INSMOD; @@ -81,11 +81,11 @@ static int pcf8583_get_datetime(struct i2c_client *client, struct rtc_time *dt) buf[4] &= 0x3f; buf[5] &= 0x1f; - dt->tm_sec = BCD_TO_BIN(buf[1]); - dt->tm_min = BCD_TO_BIN(buf[2]); - dt->tm_hour = BCD_TO_BIN(buf[3]); - dt->tm_mday = BCD_TO_BIN(buf[4]); - dt->tm_mon = BCD_TO_BIN(buf[5]); + dt->tm_sec = BCD2BIN(buf[1]); + dt->tm_min = BCD2BIN(buf[2]); + dt->tm_hour = BCD2BIN(buf[3]); + dt->tm_mday = BCD2BIN(buf[4]); + dt->tm_mon = BCD2BIN(buf[5]) - 1; } return ret == 2 ? 0 : -EIO; @@ -99,14 +99,14 @@ static int pcf8583_set_datetime(struct i2c_client *client, struct rtc_time *dt, buf[0] = 0; buf[1] = get_ctrl(client) | 0x80; buf[2] = 0; - buf[3] = BIN_TO_BCD(dt->tm_sec); - buf[4] = BIN_TO_BCD(dt->tm_min); - buf[5] = BIN_TO_BCD(dt->tm_hour); + buf[3] = BIN2BCD(dt->tm_sec); + buf[4] = BIN2BCD(dt->tm_min); + buf[5] = BIN2BCD(dt->tm_hour); if (datetoo) { len = 8; - buf[6] = BIN_TO_BCD(dt->tm_mday) | (dt->tm_year << 6); - buf[7] = BIN_TO_BCD(dt->tm_mon) | (dt->tm_wday << 5); + buf[6] = BIN2BCD(dt->tm_mday) | (dt->tm_year << 6); + buf[7] = BIN2BCD(dt->tm_mon + 1) | (dt->tm_wday << 5); } ret = i2c_master_send(client, (char *)buf, len); @@ -226,7 +226,7 @@ static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm) */ year_offset += 4; - tm->tm_year = real_year + year_offset + year[1] * 100; + tm->tm_year = (real_year + year_offset + year[1] * 100) - 1900; return 0; } @@ -237,6 +237,7 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm) unsigned char year[2], chk; struct rtc_mem cmos_year = { CMOS_YEAR, sizeof(year), year }; struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk }; + unsigned int proper_year = tm->tm_year + 1900; int ret; /* @@ -258,8 +259,8 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm) chk -= year[1] + year[0]; - year[1] = tm->tm_year / 100; - year[0] = tm->tm_year % 100; + year[1] = proper_year / 100; + year[0] = proper_year % 100; chk += year[1] + year[0]; diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 4b8a95fba1e..a1dc8c466ec 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -461,6 +461,7 @@ int dasd_eer_enable(struct dasd_device *device) cqr->device = device; cqr->retries = 255; cqr->expires = 10 * HZ; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SNSS; cqr->cpaddr->count = SNSS_DATA_SIZE; diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c index 7a76ec413a3..2a1af4e60be 100644 --- a/drivers/s390/char/tape_std.c +++ b/drivers/s390/char/tape_std.c @@ -647,7 +647,10 @@ tape_std_mtcompression(struct tape_device *device, int mt_count) return PTR_ERR(request); request->op = TO_NOP; /* setup ccws */ - *device->modeset_byte = (mt_count == 0) ? 0x00 : 0x08; + if (mt_count == 0) + *device->modeset_byte &= ~0x08; + else + *device->modeset_byte |= 0x08; tape_ccw_cc(request->cpaddr, MODE_SET_DB, 1, device->modeset_byte); tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL); /* execute it */ diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 51238e7555b..089a3ddd626 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -144,8 +144,8 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) ret = stsch(sch->schid, &sch->schib); if (ret || !sch->schib.pmcw.dnv) return -ENODEV; - if (!sch->schib.pmcw.ena || sch->schib.scsw.actl == 0) - /* Not operational or no activity -> done. */ + if (!sch->schib.pmcw.ena) + /* Not operational -> done. */ return 0; /* Stage 1: cancel io. */ if (!(sch->schib.scsw.actl & SCSW_ACTL_HALT_PEND) && @@ -334,20 +334,29 @@ ccw_device_oper_notify(struct work_struct *work) struct ccw_device *cdev; struct subchannel *sch; int ret; + unsigned long flags; priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; + spin_lock_irqsave(cdev->ccwlock, flags); sch = to_subchannel(cdev->dev.parent); - ret = (sch->driver && sch->driver->notify) ? - sch->driver->notify(&sch->dev, CIO_OPER) : 0; - if (!ret) - /* Driver doesn't want device back. */ - ccw_device_do_unreg_rereg(work); - else { + if (sch->driver && sch->driver->notify) { + spin_unlock_irqrestore(cdev->ccwlock, flags); + ret = sch->driver->notify(&sch->dev, CIO_OPER); + spin_lock_irqsave(cdev->ccwlock, flags); + } else + ret = 0; + if (ret) { /* Reenable channel measurements, if needed. */ + spin_unlock_irqrestore(cdev->ccwlock, flags); cmf_reenable(cdev); + spin_lock_irqsave(cdev->ccwlock, flags); wake_up(&cdev->private->wait_q); } + spin_unlock_irqrestore(cdev->ccwlock, flags); + if (!ret) + /* Driver doesn't want device back. */ + ccw_device_do_unreg_rereg(work); } /* @@ -534,15 +543,21 @@ ccw_device_nopath_notify(struct work_struct *work) struct ccw_device *cdev; struct subchannel *sch; int ret; + unsigned long flags; priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; + spin_lock_irqsave(cdev->ccwlock, flags); sch = to_subchannel(cdev->dev.parent); /* Extra sanity. */ if (sch->lpm) - return; - ret = (sch->driver && sch->driver->notify) ? - sch->driver->notify(&sch->dev, CIO_NO_PATH) : 0; + goto out_unlock; + if (sch->driver && sch->driver->notify) { + spin_unlock_irqrestore(cdev->ccwlock, flags); + ret = sch->driver->notify(&sch->dev, CIO_NO_PATH); + spin_lock_irqsave(cdev->ccwlock, flags); + } else + ret = 0; if (!ret) { if (get_device(&sch->dev)) { /* Driver doesn't want to keep device. */ @@ -562,6 +577,8 @@ ccw_device_nopath_notify(struct work_struct *work) cdev->private->state = DEV_STATE_DISCONNECTED; wake_up(&cdev->private->wait_q); } +out_unlock: + spin_unlock_irqrestore(cdev->ccwlock, flags); } void @@ -607,10 +624,13 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) default: /* Reset oper notify indication after verify error. */ cdev->private->flags.donotify = 0; - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, &cdev->private->kick_work); - ccw_device_done(cdev, DEV_STATE_NOT_OPER); + if (cdev->online) { + PREPARE_WORK(&cdev->private->kick_work, + ccw_device_nopath_notify); + queue_work(ccw_device_notify_work, + &cdev->private->kick_work); + } else + ccw_device_done(cdev, DEV_STATE_NOT_OPER); break; } } @@ -756,15 +776,22 @@ static void ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event) { struct subchannel *sch; + int ret; sch = to_subchannel(cdev->dev.parent); - if (sch->driver->notify && - sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) { - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - wake_up(&cdev->private->wait_q); - return; + if (sch->driver->notify) { + spin_unlock_irq(cdev->ccwlock); + ret = sch->driver->notify(&sch->dev, + sch->lpm ? CIO_GONE : CIO_NO_PATH); + spin_lock_irq(cdev->ccwlock); + } else + ret = 0; + if (ret) { + ccw_device_set_timeout(cdev, 0); + cdev->private->flags.fake_irb = 0; + cdev->private->state = DEV_STATE_DISCONNECTED; + wake_up(&cdev->private->wait_q); + return; } cdev->private->state = DEV_STATE_NOT_OPER; cio_disable_subchannel(sch); @@ -969,18 +996,12 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); ccw_device_set_timeout(cdev, 0); + /* Start delayed path verification. */ + ccw_device_online_verify(cdev, 0); /* OK, i/o is dead now. Call interrupt handler. */ - cdev->private->state = DEV_STATE_ONLINE; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO)); - if (!sch->lpm) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, &cdev->private->kick_work); - } else if (cdev->private->flags.doverify) - /* Start delayed path verification. */ - ccw_device_online_verify(cdev, 0); } static void @@ -993,21 +1014,8 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_set_timeout(cdev, 3*HZ); return; } - if (ret == -ENODEV) { - struct subchannel *sch; - - sch = to_subchannel(cdev->dev.parent); - if (!sch->lpm) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, - &cdev->private->kick_work); - } else - dev_fsm_event(cdev, DEV_EVENT_NOTOPER); - return; - } - //FIXME: Can we get here? - cdev->private->state = DEV_STATE_ONLINE; + /* Start delayed path verification. */ + ccw_device_online_verify(cdev, 0); if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO)); @@ -1025,26 +1033,11 @@ void device_kill_io(struct subchannel *sch) cdev->private->state = DEV_STATE_TIMEOUT_KILL; return; } - if (ret == -ENODEV) { - if (!sch->lpm) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, - &cdev->private->kick_work); - } else - dev_fsm_event(cdev, DEV_EVENT_NOTOPER); - return; - } + /* Start delayed path verification. */ + ccw_device_online_verify(cdev, 0); if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO)); - if (!sch->lpm) { - PREPARE_WORK(&cdev->private->kick_work, - ccw_device_nopath_notify); - queue_work(ccw_device_notify_work, &cdev->private->kick_work); - } else - /* Start delayed path verification. */ - ccw_device_online_verify(cdev, 0); } static void diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 2257e45594b..d8a86f5af37 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -3654,7 +3654,7 @@ qeth_verify_vlan_dev(struct net_device *dev, struct qeth_card *card) return rc; for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++){ - if (vg->vlan_devices[i] == dev){ + if (vlan_group_get_device(vg, i) == dev){ rc = QETH_VLAN_CARD; break; } @@ -5261,7 +5261,7 @@ qeth_free_vlan_addresses4(struct qeth_card *card, unsigned short vid) QETH_DBF_TEXT(trace, 4, "frvaddr4"); rcu_read_lock(); - in_dev = __in_dev_get_rcu(card->vlangrp->vlan_devices[vid]); + in_dev = __in_dev_get_rcu(vlan_group_get_device(card->vlangrp, vid)); if (!in_dev) goto out; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { @@ -5288,7 +5288,7 @@ qeth_free_vlan_addresses6(struct qeth_card *card, unsigned short vid) QETH_DBF_TEXT(trace, 4, "frvaddr6"); - in6_dev = in6_dev_get(card->vlangrp->vlan_devices[vid]); + in6_dev = in6_dev_get(vlan_group_get_device(card->vlangrp, vid)); if (!in6_dev) return; for (ifa = in6_dev->addr_list; ifa; ifa = ifa->lst_next){ @@ -5360,7 +5360,7 @@ qeth_layer2_process_vlans(struct qeth_card *card, int clear) if (!card->vlangrp) return; for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { - if (card->vlangrp->vlan_devices[i] == NULL) + if (vlan_group_get_device(card->vlangrp, i) == NULL) continue; if (clear) qeth_layer2_send_setdelvlan(card, i, IPA_CMD_DELVLAN); @@ -5398,8 +5398,7 @@ qeth_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) spin_lock_irqsave(&card->vlanlock, flags); /* unregister IP addresses of vlan device */ qeth_free_vlan_addresses(card, vid); - if (card->vlangrp) - card->vlangrp->vlan_devices[vid] = NULL; + vlan_group_set_device(card->vlangrp, vid, NULL); spin_unlock_irqrestore(&card->vlanlock, flags); if (card->options.layer2) qeth_layer2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN); @@ -5662,10 +5661,11 @@ qeth_add_vlan_mc(struct qeth_card *card) vg = card->vlangrp; for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { - if (vg->vlan_devices[i] == NULL || - !(vg->vlan_devices[i]->flags & IFF_UP)) + struct net_device *netdev = vlan_group_get_device(vg, i); + if (netdev == NULL || + !(netdev->flags & IFF_UP)) continue; - in_dev = in_dev_get(vg->vlan_devices[i]); + in_dev = in_dev_get(netdev); if (!in_dev) continue; read_lock(&in_dev->mc_list_lock); @@ -5749,10 +5749,11 @@ qeth_add_vlan_mc6(struct qeth_card *card) vg = card->vlangrp; for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) { - if (vg->vlan_devices[i] == NULL || - !(vg->vlan_devices[i]->flags & IFF_UP)) + struct net_device *netdev = vlan_group_get_device(vg, i); + if (netdev == NULL || + !(netdev->flags & IFF_UP)) continue; - in_dev = in6_dev_get(vg->vlan_devices[i]); + in_dev = in6_dev_get(netdev); if (!in_dev) continue; read_lock(&in_dev->lock); diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig index 3a8152906bf..35a73168333 100644 --- a/drivers/sbus/char/Kconfig +++ b/drivers/sbus/char/Kconfig @@ -46,13 +46,6 @@ config SUN_VIDEOPIX based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and SVIDEO signals. -config SUN_AURORA - tristate "Aurora Multiboard 1600se (EXPERIMENTAL)" - depends on EXPERIMENTAL && BROKEN - help - The Aurora Multiboard is a multi-port high-speed serial controller. - If you have one of these, say Y. - config TADPOLE_TS102_UCTRL tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)" depends on EXPERIMENTAL && SPARC32 diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile index 3a5ea1dc789..7ab060e9a5f 100644 --- a/drivers/sbus/char/Makefile +++ b/drivers/sbus/char/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_SUN_OPENPROMIO) += openprom.o obj-$(CONFIG_SUN_MOSTEK_RTC) += rtc.o obj-$(CONFIG_SUN_BPP) += bpp.o obj-$(CONFIG_SUN_VIDEOPIX) += vfc.o -obj-$(CONFIG_SUN_AURORA) += aurora.o obj-$(CONFIG_TADPOLE_TS102_UCTRL) += uctrl.o obj-$(CONFIG_SUN_JSFLASH) += jsflash.o obj-$(CONFIG_BBC_I2C) += bbc.o diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c deleted file mode 100644 index a54b4ac6756..00000000000 --- a/drivers/sbus/char/aurora.c +++ /dev/null @@ -1,2364 +0,0 @@ -/* $Id: aurora.c,v 1.19 2002/01/08 16:00:16 davem Exp $ - * linux/drivers/sbus/char/aurora.c -- Aurora multiport driver - * - * Copyright (c) 1999 by Oliver Aldulea (oli at bv dot ro) - * - * This code is based on the RISCom/8 multiport serial driver written - * by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial - * driver, written by Linus Torvalds, Theodore T'so and others. - * The Aurora multiport programming info was obtained mainly from the - * Cirrus Logic CD180 documentation (available on the web), and by - * doing heavy tests on the board. Many thanks to Eddie C. Dost for the - * help on the sbus interface. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Revision 1.0 - * - * This is the first public release. - * - * Most of the information you need is in the aurora.h file. Please - * read that file before reading this one. - * - * Several parts of the code do not have comments yet. - * - * n.b. The board can support 115.2 bit rates, but only on a few - * ports. The total badwidth of one chip (ports 0-7 or 8-15) is equal - * to OSC_FREQ div 16. In case of my board, each chip can take 6 - * channels of 115.2 kbaud. This information is not well-tested. - * - * Fixed to use tty_get_baud_rate(). - * Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12 - */ - -#include <linux/module.h> - -#include <linux/errno.h> -#include <linux/sched.h> -#ifdef AURORA_INT_DEBUG -#include <linux/timer.h> -#endif -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/mm.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/bitops.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/oplib.h> -#include <asm/system.h> -#include <asm/kdebug.h> -#include <asm/sbus.h> -#include <asm/uaccess.h> - -#include "aurora.h" -#include "cd180.h" - -unsigned char irqs[4] = { - 0, 0, 0, 0 -}; - -#ifdef AURORA_INT_DEBUG -int irqhit=0; -#endif - -static struct tty_driver *aurora_driver; -static struct Aurora_board aurora_board[AURORA_NBOARD] = { - {0,}, -}; - -static struct Aurora_port aurora_port[AURORA_TNPORTS] = { - { 0, }, -}; - -/* no longer used. static struct Aurora_board * IRQ_to_board[16] = { NULL, } ;*/ -static unsigned char * tmp_buf = NULL; - -DECLARE_TASK_QUEUE(tq_aurora); - -static inline int aurora_paranoia_check(struct Aurora_port const * port, - char *name, const char *routine) -{ -#ifdef AURORA_PARANOIA_CHECK - static const char *badmagic = - KERN_DEBUG "aurora: Warning: bad aurora port magic number for device %s in %s\n"; - static const char *badinfo = - KERN_DEBUG "aurora: Warning: null aurora port for device %s in %s\n"; - - if (!port) { - printk(badinfo, name, routine); - return 1; - } - if (port->magic != AURORA_MAGIC) { - printk(badmagic, name, routine); - return 1; - } -#endif - return 0; -} - -/* - * - * Service functions for aurora driver. - * - */ - -/* Get board number from pointer */ -static inline int board_No (struct Aurora_board const * bp) -{ - return bp - aurora_board; -} - -/* Get port number from pointer */ -static inline int port_No (struct Aurora_port const * port) -{ - return AURORA_PORT(port - aurora_port); -} - -/* Get pointer to board from pointer to port */ -static inline struct Aurora_board * port_Board(struct Aurora_port const * port) -{ - return &aurora_board[AURORA_BOARD(port - aurora_port)]; -} - -/* Wait for Channel Command Register ready */ -static inline void aurora_wait_CCR(struct aurora_reg128 * r) -{ - unsigned long delay; - -#ifdef AURORA_DEBUG -printk("aurora_wait_CCR\n"); -#endif - /* FIXME: need something more descriptive than 100000 :) */ - for (delay = 100000; delay; delay--) - if (!sbus_readb(&r->r[CD180_CCR])) - return; - printk(KERN_DEBUG "aurora: Timeout waiting for CCR.\n"); -} - -/* - * aurora probe functions. - */ - -/* Must be called with enabled interrupts */ -static inline void aurora_long_delay(unsigned long delay) -{ - unsigned long i; - -#ifdef AURORA_DEBUG - printk("aurora_long_delay: start\n"); -#endif - for (i = jiffies + delay; time_before(jiffies, i); ) ; -#ifdef AURORA_DEBUG - printk("aurora_long_delay: end\n"); -#endif -} - -/* Reset and setup CD180 chip */ -static int aurora_init_CD180(struct Aurora_board * bp, int chip) -{ - unsigned long flags; - int id; - -#ifdef AURORA_DEBUG - printk("aurora_init_CD180: start %d:%d\n", - board_No(bp), chip); -#endif - save_flags(flags); cli(); - sbus_writeb(0, &bp->r[chip]->r[CD180_CAR]); - sbus_writeb(0, &bp->r[chip]->r[CD180_GSVR]); - - /* Wait for CCR ready */ - aurora_wait_CCR(bp->r[chip]); - - /* Reset CD180 chip */ - sbus_writeb(CCR_HARDRESET, &bp->r[chip]->r[CD180_CCR]); - udelay(1); - sti(); - id=1000; - while((--id) && - (sbus_readb(&bp->r[chip]->r[CD180_GSVR])!=0xff))udelay(100); - if(!id) { - printk(KERN_ERR "aurora%d: Chip %d failed init.\n", - board_No(bp), chip); - restore_flags(flags); - return(-1); - } - cli(); - sbus_writeb((board_No(bp)<<5)|((chip+1)<<3), - &bp->r[chip]->r[CD180_GSVR]); /* Set ID for this chip */ - sbus_writeb(0x80|bp->ACK_MINT, - &bp->r[chip]->r[CD180_MSMR]); /* Prio for modem intr */ - sbus_writeb(0x80|bp->ACK_TINT, - &bp->r[chip]->r[CD180_TSMR]); /* Prio for transmitter intr */ - sbus_writeb(0x80|bp->ACK_RINT, - &bp->r[chip]->r[CD180_RSMR]); /* Prio for receiver intr */ - /* Setting up prescaler. We need 4 tick per 1 ms */ - sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) >> 8, - &bp->r[chip]->r[CD180_PPRH]); - sbus_writeb((bp->oscfreq/(1000000/AURORA_TPS)) & 0xff, - &bp->r[chip]->r[CD180_PPRL]); - - sbus_writeb(SRCR_AUTOPRI|SRCR_GLOBPRI, - &bp->r[chip]->r[CD180_SRCR]); - - id = sbus_readb(&bp->r[chip]->r[CD180_GFRCR]); - printk(KERN_INFO "aurora%d: Chip %d id %02x: ", - board_No(bp), chip,id); - if(sbus_readb(&bp->r[chip]->r[CD180_SRCR]) & 128) { - switch (id) { - case 0x82:printk("CL-CD1864 rev A\n");break; - case 0x83:printk("CL-CD1865 rev A\n");break; - case 0x84:printk("CL-CD1865 rev B\n");break; - case 0x85:printk("CL-CD1865 rev C\n");break; - default:printk("Unknown.\n"); - }; - } else { - switch (id) { - case 0x81:printk("CL-CD180 rev B\n");break; - case 0x82:printk("CL-CD180 rev C\n");break; - default:printk("Unknown.\n"); - }; - } - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_init_CD180: end\n"); -#endif - return 0; -} - -static int valid_irq(unsigned char irq) -{ -int i; -for(i=0;i<TYPE_1_IRQS;i++) - if (type_1_irq[i]==irq) return 1; -return 0; -} - -static irqreturn_t aurora_interrupt(int irq, void * dev_id); - -/* Main probing routine, also sets irq. */ -static int aurora_probe(void) -{ - struct sbus_bus *sbus; - struct sbus_dev *sdev; - int grrr; - char buf[30]; - int bn = 0; - struct Aurora_board *bp; - - for_each_sbus(sbus) { - for_each_sbusdev(sdev, sbus) { -/* printk("Try: %x %s\n",sdev,sdev->prom_name);*/ - if (!strcmp(sdev->prom_name, "sio16")) { -#ifdef AURORA_DEBUG - printk(KERN_INFO "aurora: sio16 at %p\n",sdev); -#endif - if((sdev->reg_addrs[0].reg_size!=1) && - (sdev->reg_addrs[1].reg_size!=128) && - (sdev->reg_addrs[2].reg_size!=128) && - (sdev->reg_addrs[3].reg_size!=4)) { - printk(KERN_ERR "aurora%d: registers' sizes " - "do not match.\n", bn); - break; - } - bp = &aurora_board[bn]; - bp->r0 = (struct aurora_reg1 *) - sbus_ioremap(&sdev->resource[0], 0, - sdev->reg_addrs[0].reg_size, - "sio16"); - if (bp->r0 == NULL) { - printk(KERN_ERR "aurora%d: can't map " - "reg_addrs[0]\n", bn); - break; - } -#ifdef AURORA_DEBUG - printk("Map reg 0: %p\n", bp->r0); -#endif - bp->r[0] = (struct aurora_reg128 *) - sbus_ioremap(&sdev->resource[1], 0, - sdev->reg_addrs[1].reg_size, - "sio16"); - if (bp->r[0] == NULL) { - printk(KERN_ERR "aurora%d: can't map " - "reg_addrs[1]\n", bn); - break; - } -#ifdef AURORA_DEBUG - printk("Map reg 1: %p\n", bp->r[0]); -#endif - bp->r[1] = (struct aurora_reg128 *) - sbus_ioremap(&sdev->resource[2], 0, - sdev->reg_addrs[2].reg_size, - "sio16"); - if (bp->r[1] == NULL) { - printk(KERN_ERR "aurora%d: can't map " - "reg_addrs[2]\n", bn); - break; - } -#ifdef AURORA_DEBUG - printk("Map reg 2: %p\n", bp->r[1]); -#endif - bp->r3 = (struct aurora_reg4 *) - sbus_ioremap(&sdev->resource[3], 0, - sdev->reg_addrs[3].reg_size, - "sio16"); - if (bp->r3 == NULL) { - printk(KERN_ERR "aurora%d: can't map " - "reg_addrs[3]\n", bn); - break; - } -#ifdef AURORA_DEBUG - printk("Map reg 3: %p\n", bp->r3); -#endif - /* Variables setup */ - bp->flags = 0; -#ifdef AURORA_DEBUG - grrr=prom_getint(sdev->prom_node,"intr"); - printk("intr pri %d\n", grrr); -#endif - if ((bp->irq=irqs[bn]) && valid_irq(bp->irq) && - !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) { - free_irq(bp->irq|0x30, bp); - } else - if ((bp->irq=prom_getint(sdev->prom_node, "bintr")) && valid_irq(bp->irq) && - !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) { - free_irq(bp->irq|0x30, bp); - } else - if ((bp->irq=prom_getint(sdev->prom_node, "intr")) && valid_irq(bp->irq) && - !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) { - free_irq(bp->irq|0x30, bp); - } else - for(grrr=0;grrr<TYPE_1_IRQS;grrr++) { - if ((bp->irq=type_1_irq[grrr])&&!request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) { - free_irq(bp->irq|0x30, bp); - break; - } else { - printk(KERN_ERR "aurora%d: Could not get an irq for this board !!!\n",bn); - bp->flags=0xff; - } - } - if(bp->flags==0xff)break; - printk(KERN_INFO "aurora%d: irq %d\n",bn,bp->irq&0x0f); - buf[0]=0; - grrr=prom_getproperty(sdev->prom_node,"dtr_rts",buf,sizeof(buf)); - if(!strcmp(buf,"swapped")){ - printk(KERN_INFO "aurora%d: Swapped DTR and RTS\n",bn); - bp->DTR=MSVR_RTS; - bp->RTS=MSVR_DTR; - bp->MSVDTR=CD180_MSVRTS; - bp->MSVRTS=CD180_MSVDTR; - bp->flags|=AURORA_BOARD_DTR_FLOW_OK; - }else{ - #ifdef AURORA_FORCE_DTR_FLOW - printk(KERN_INFO "aurora%d: Forcing swapped DTR-RTS\n",bn); - bp->DTR=MSVR_RTS; - bp->RTS=MSVR_DTR; - bp->MSVDTR=CD180_MSVRTS; - bp->MSVRTS=CD180_MSVDTR; - bp->flags|=AURORA_BOARD_DTR_FLOW_OK; - #else - printk(KERN_INFO "aurora%d: Normal DTR and RTS\n",bn); - bp->DTR=MSVR_DTR; - bp->RTS=MSVR_RTS; - bp->MSVDTR=CD180_MSVDTR; - bp->MSVRTS=CD180_MSVRTS; - #endif - } - bp->oscfreq=prom_getint(sdev->prom_node,"clk")*100; - printk(KERN_INFO "aurora%d: Oscillator: %d Hz\n",bn,bp->oscfreq); - grrr=prom_getproperty(sdev->prom_node,"chip",buf,sizeof(buf)); - printk(KERN_INFO "aurora%d: Chips: %s\n",bn,buf); - grrr=prom_getproperty(sdev->prom_node,"manu",buf,sizeof(buf)); - printk(KERN_INFO "aurora%d: Manufacturer: %s\n",bn,buf); - grrr=prom_getproperty(sdev->prom_node,"model",buf,sizeof(buf)); - printk(KERN_INFO "aurora%d: Model: %s\n",bn,buf); - grrr=prom_getproperty(sdev->prom_node,"rev",buf,sizeof(buf)); - printk(KERN_INFO "aurora%d: Revision: %s\n",bn,buf); - grrr=prom_getproperty(sdev->prom_node,"mode",buf,sizeof(buf)); - printk(KERN_INFO "aurora%d: Mode: %s\n",bn,buf); - #ifdef MODULE - bp->count=0; - #endif - bp->flags = AURORA_BOARD_PRESENT; - /* hardware ack */ - bp->ACK_MINT=1; - bp->ACK_TINT=2; - bp->ACK_RINT=3; - bn++; - } - } - } - return bn; -} - -static void aurora_release_io_range(struct Aurora_board *bp) -{ - sbus_iounmap((unsigned long)bp->r0, 1); - sbus_iounmap((unsigned long)bp->r[0], 128); - sbus_iounmap((unsigned long)bp->r[1], 128); - sbus_iounmap((unsigned long)bp->r3, 4); -} - -static inline void aurora_mark_event(struct Aurora_port * port, int event) -{ -#ifdef AURORA_DEBUG - printk("aurora_mark_event: start\n"); -#endif - set_bit(event, &port->event); - queue_task(&port->tqueue, &tq_aurora); - mark_bh(AURORA_BH); -#ifdef AURORA_DEBUG - printk("aurora_mark_event: end\n"); -#endif -} - -static __inline__ struct Aurora_port * aurora_get_port(struct Aurora_board const * bp, - int chip, - unsigned char const *what) -{ - unsigned char channel; - struct Aurora_port * port; - - channel = ((chip << 3) | - ((sbus_readb(&bp->r[chip]->r[CD180_GSCR]) & GSCR_CHAN) >> GSCR_CHAN_OFF)); - port = &aurora_port[board_No(bp) * AURORA_NPORT * AURORA_NCD180 + channel]; - if (port->flags & ASYNC_INITIALIZED) - return port; - - printk(KERN_DEBUG "aurora%d: %s interrupt from invalid port %d\n", - board_No(bp), what, channel); - return NULL; -} - -static void aurora_receive_exc(struct Aurora_board const * bp, int chip) -{ - struct Aurora_port *port; - struct tty_struct *tty; - unsigned char status; - unsigned char ch; - - if (!(port = aurora_get_port(bp, chip, "Receive_x"))) - return; - - tty = port->tty; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { -#ifdef AURORA_INTNORM - printk("aurora%d: port %d: Working around flip buffer overflow.\n", - board_No(bp), port_No(port)); -#endif - return; - } - -#ifdef AURORA_REPORT_OVERRUN - status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]); - if (status & RCSR_OE) { - port->overrun++; -#if 1 - printk("aurora%d: port %d: Overrun. Total %ld overruns.\n", - board_No(bp), port_No(port), port->overrun); -#endif - } - status &= port->mark_mask; -#else - status = sbus_readb(&bp->r[chip]->r[CD180_RCSR]) & port->mark_mask; -#endif - ch = sbus_readb(&bp->r[chip]->r[CD180_RDR]); - if (!status) - return; - - if (status & RCSR_TOUT) { -/* printk("aurora%d: port %d: Receiver timeout. Hardware problems ?\n", - board_No(bp), port_No(port));*/ - return; - - } else if (status & RCSR_BREAK) { - printk(KERN_DEBUG "aurora%d: port %d: Handling break...\n", - board_No(bp), port_No(port)); - *tty->flip.flag_buf_ptr++ = TTY_BREAK; - if (port->flags & ASYNC_SAK) - do_SAK(tty); - - } else if (status & RCSR_PE) - *tty->flip.flag_buf_ptr++ = TTY_PARITY; - - else if (status & RCSR_FE) - *tty->flip.flag_buf_ptr++ = TTY_FRAME; - - else if (status & RCSR_OE) - *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; - - else - *tty->flip.flag_buf_ptr++ = 0; - - *tty->flip.char_buf_ptr++ = ch; - tty->flip.count++; - queue_task(&tty->flip.tqueue, &tq_timer); -} - -static void aurora_receive(struct Aurora_board const * bp, int chip) -{ - struct Aurora_port *port; - struct tty_struct *tty; - unsigned char count,cnt; - - if (!(port = aurora_get_port(bp, chip, "Receive"))) - return; - - tty = port->tty; - - count = sbus_readb(&bp->r[chip]->r[CD180_RDCR]); - -#ifdef AURORA_REPORT_FIFO - port->hits[count > 8 ? 9 : count]++; -#endif - - while (count--) { - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { -#ifdef AURORA_INTNORM - printk("aurora%d: port %d: Working around flip buffer overflow.\n", - board_No(bp), port_No(port)); -#endif - break; - } - cnt = sbus_readb(&bp->r[chip]->r[CD180_RDR]); - *tty->flip.char_buf_ptr++ = cnt; - *tty->flip.flag_buf_ptr++ = 0; - tty->flip.count++; - } - queue_task(&tty->flip.tqueue, &tq_timer); -} - -static void aurora_transmit(struct Aurora_board const * bp, int chip) -{ - struct Aurora_port *port; - struct tty_struct *tty; - unsigned char count; - - if (!(port = aurora_get_port(bp, chip, "Transmit"))) - return; - - tty = port->tty; - - if (port->SRER & SRER_TXEMPTY) { - /* FIFO drained */ - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - port->SRER &= ~SRER_TXEMPTY; - sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]); - return; - } - - if ((port->xmit_cnt <= 0 && !port->break_length) - || tty->stopped || tty->hw_stopped) { - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - port->SRER &= ~SRER_TXRDY; - sbus_writeb(port->SRER, - &bp->r[chip]->r[CD180_SRER]); - return; - } - - if (port->break_length) { - if (port->break_length > 0) { - if (port->COR2 & COR2_ETC) { - sbus_writeb(CD180_C_ESC, - &bp->r[chip]->r[CD180_TDR]); - sbus_writeb(CD180_C_SBRK, - &bp->r[chip]->r[CD180_TDR]); - port->COR2 &= ~COR2_ETC; - } - count = min(port->break_length, 0xff); - sbus_writeb(CD180_C_ESC, - &bp->r[chip]->r[CD180_TDR]); - sbus_writeb(CD180_C_DELAY, - &bp->r[chip]->r[CD180_TDR]); - sbus_writeb(count, - &bp->r[chip]->r[CD180_TDR]); - if (!(port->break_length -= count)) - port->break_length--; - } else { - sbus_writeb(CD180_C_ESC, - &bp->r[chip]->r[CD180_TDR]); - sbus_writeb(CD180_C_EBRK, - &bp->r[chip]->r[CD180_TDR]); - sbus_writeb(port->COR2, - &bp->r[chip]->r[CD180_COR2]); - aurora_wait_CCR(bp->r[chip]); - sbus_writeb(CCR_CORCHG2, - &bp->r[chip]->r[CD180_CCR]); - port->break_length = 0; - } - return; - } - - count = CD180_NFIFO; - do { - u8 byte = port->xmit_buf[port->xmit_tail++]; - - sbus_writeb(byte, &bp->r[chip]->r[CD180_TDR]); - port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE-1); - if (--port->xmit_cnt <= 0) - break; - } while (--count > 0); - - if (port->xmit_cnt <= 0) { - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - port->SRER &= ~SRER_TXRDY; - sbus_writeb(port->SRER, - &bp->r[chip]->r[CD180_SRER]); - } - if (port->xmit_cnt <= port->wakeup_chars) - aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP); -} - -static void aurora_check_modem(struct Aurora_board const * bp, int chip) -{ - struct Aurora_port *port; - struct tty_struct *tty; - unsigned char mcr; - - if (!(port = aurora_get_port(bp, chip, "Modem"))) - return; - - tty = port->tty; - - mcr = sbus_readb(&bp->r[chip]->r[CD180_MCR]); - if (mcr & MCR_CDCHG) { - if (sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD) - wake_up_interruptible(&port->open_wait); - else - schedule_task(&port->tqueue_hangup); - } - -/* We don't have such things yet. My aurora board has DTR and RTS swapped, but that doesn't count in this driver. Let's hope - * Aurora didn't made any boards with CTS or DSR broken... - */ -/* #ifdef AURORA_BRAIN_DAMAGED_CTS - if (mcr & MCR_CTSCHG) { - if (aurora_in(bp, CD180_MSVR) & MSVR_CTS) { - tty->hw_stopped = 0; - port->SRER |= SRER_TXRDY; - if (port->xmit_cnt <= port->wakeup_chars) - aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP); - } else { - tty->hw_stopped = 1; - port->SRER &= ~SRER_TXRDY; - } - sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]); - } - if (mcr & MCR_DSRCHG) { - if (aurora_in(bp, CD180_MSVR) & MSVR_DSR) { - tty->hw_stopped = 0; - port->SRER |= SRER_TXRDY; - if (port->xmit_cnt <= port->wakeup_chars) - aurora_mark_event(port, RS_EVENT_WRITE_WAKEUP); - } else { - tty->hw_stopped = 1; - port->SRER &= ~SRER_TXRDY; - } - sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]); - } -#endif AURORA_BRAIN_DAMAGED_CTS */ - - /* Clear change bits */ - sbus_writeb(0, &bp->r[chip]->r[CD180_MCR]); -} - -/* The main interrupt processing routine */ -static irqreturn_t aurora_interrupt(int irq, void * dev_id) -{ - unsigned char status; - unsigned char ack,chip/*,chip_id*/; - struct Aurora_board * bp = (struct Aurora_board *) dev_id; - unsigned long loop = 0; - -#ifdef AURORA_INT_DEBUG - printk("IRQ%d %d\n",irq,++irqhit); -#ifdef AURORA_FLOODPRO - if (irqhit>=AURORA_FLOODPRO) - sbus_writeb(8, &bp->r0->r); -#endif -#endif - -/* old bp = IRQ_to_board[irq&0x0f];*/ - - if (!bp || !(bp->flags & AURORA_BOARD_ACTIVE)) - return IRQ_NONE; - -/* The while() below takes care of this. - status = sbus_readb(&bp->r[0]->r[CD180_SRSR]); -#ifdef AURORA_INT_DEBUG - printk("mumu: %02x\n", status); -#endif - if (!(status&SRSR_ANYINT)) - return IRQ_NONE; * Nobody has anything to say, so exit * -*/ - while ((loop++ < 48) && - (status = sbus_readb(&bp->r[0]->r[CD180_SRSR]) & SRSR_ANYINT)){ -#ifdef AURORA_INT_DEBUG - printk("SRSR: %02x\n", status); -#endif - if (status & SRSR_REXT) { - ack = sbus_readb(&bp->r3->r[bp->ACK_RINT]); -#ifdef AURORA_INT_DEBUG - printk("R-ACK %02x\n", ack); -#endif - if ((ack >> 5) == board_No(bp)) { - if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) { - if ((ack&GSVR_ITMASK)==GSVR_IT_RGD) { - aurora_receive(bp,chip); - sbus_writeb(0, - &bp->r[chip]->r[CD180_EOSRR]); - } else if ((ack & GSVR_ITMASK) == GSVR_IT_REXC) { - aurora_receive_exc(bp,chip); - sbus_writeb(0, - &bp->r[chip]->r[CD180_EOSRR]); - } - } - } - } else if (status & SRSR_TEXT) { - ack = sbus_readb(&bp->r3->r[bp->ACK_TINT]); -#ifdef AURORA_INT_DEBUG - printk("T-ACK %02x\n", ack); -#endif - if ((ack >> 5) == board_No(bp)) { - if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) { - if ((ack&GSVR_ITMASK)==GSVR_IT_TX) { - aurora_transmit(bp,chip); - sbus_writeb(0, - &bp->r[chip]->r[CD180_EOSRR]); - } - } - } - } else if (status & SRSR_MEXT) { - ack = sbus_readb(&bp->r3->r[bp->ACK_MINT]); -#ifdef AURORA_INT_DEBUG - printk("M-ACK %02x\n", ack); -#endif - if ((ack >> 5) == board_No(bp)) { - if ((chip = ((ack>>3)&3)-1) < AURORA_NCD180) { - if ((ack&GSVR_ITMASK)==GSVR_IT_MDM) { - aurora_check_modem(bp,chip); - sbus_writeb(0, - &bp->r[chip]->r[CD180_EOSRR]); - } - } - } - } - } -/* I guess this faster code can be used with CD1865, using AUROPRI and GLOBPRI. */ -#if 0 - while ((loop++ < 48)&&(status=bp->r[0]->r[CD180_SRSR]&SRSR_ANYINT)){ -#ifdef AURORA_INT_DEBUG - printk("SRSR: %02x\n",status); -#endif - ack = sbus_readb(&bp->r3->r[0]); -#ifdef AURORA_INT_DEBUG - printk("ACK: %02x\n",ack); -#endif - if ((ack>>5)==board_No(bp)) { - if ((chip=((ack>>3)&3)-1) < AURORA_NCD180) { - ack&=GSVR_ITMASK; - if (ack==GSVR_IT_RGD) { - aurora_receive(bp,chip); - sbus_writeb(0, - &bp->r[chip]->r[CD180_EOSRR]); - } else if (ack==GSVR_IT_REXC) { - aurora_receive_exc(bp,chip); - sbus_writeb(0, - &bp->r[chip]->r[CD180_EOSRR]); - } else if (ack==GSVR_IT_TX) { - aurora_transmit(bp,chip); - sbus_writeb(0, - &bp->r[chip]->r[CD180_EOSRR]); - } else if (ack==GSVR_IT_MDM) { - aurora_check_modem(bp,chip); - sbus_writeb(0, - &bp->r[chip]->r[CD180_EOSRR]); - } - } - } - } -#endif - -/* This is the old handling routine, used in riscom8 for only one CD180. I keep it here for reference. */ -#if 0 - for(chip=0;chip<AURORA_NCD180;chip++){ - chip_id=(board_No(bp)<<5)|((chip+1)<<3); - loop=0; - while ((loop++ < 1) && - ((status = sbus_readb(&bp->r[chip]->r[CD180_SRSR])) & - (SRSR_TEXT | SRSR_MEXT | SRSR_REXT))) { - - if (status & SRSR_REXT) { - ack = sbus_readb(&bp->r3->r[bp->ACK_RINT]); - if (ack == (chip_id | GSVR_IT_RGD)) { -#ifdef AURORA_INTMSG - printk("RX ACK\n"); -#endif - aurora_receive(bp,chip); - } else if (ack == (chip_id | GSVR_IT_REXC)) { -#ifdef AURORA_INTMSG - printk("RXC ACK\n"); -#endif - aurora_receive_exc(bp,chip); - } else { -#ifdef AURORA_INTNORM - printk("aurora%d-%d: Bad receive ack 0x%02x.\n", - board_No(bp), chip, ack); -#endif - } - } else if (status & SRSR_TEXT) { - ack = sbus_readb(&bp->r3->r[bp->ACK_TINT]); - if (ack == (chip_id | GSVR_IT_TX)){ -#ifdef AURORA_INTMSG - printk("TX ACK\n"); -#endif - aurora_transmit(bp,chip); - } else { -#ifdef AURORA_INTNORM - printk("aurora%d-%d: Bad transmit ack 0x%02x.\n", - board_No(bp), chip, ack); -#endif - } - } else if (status & SRSR_MEXT) { - ack = sbus_readb(&bp->r3->r[bp->ACK_MINT]); - if (ack == (chip_id | GSVR_IT_MDM)){ -#ifdef AURORA_INTMSG - printk("MDM ACK\n"); -#endif - aurora_check_modem(bp,chip); - } else { -#ifdef AURORA_INTNORM - printk("aurora%d-%d: Bad modem ack 0x%02x.\n", - board_No(bp), chip, ack); -#endif - } - } - sbus_writeb(0, &bp->r[chip]->r[CD180_EOSRR]); - } - } -#endif - - return IRQ_HANDLED; -} - -#ifdef AURORA_INT_DEBUG -static void aurora_timer (unsigned long ignored); - -static DEFINE_TIMER(aurora_poll_timer, aurora_timer, 0, 0); - -static void -aurora_timer (unsigned long ignored) -{ - unsigned long flags; - int i; - - save_flags(flags); cli(); - - printk("SRSR: %02x,%02x - ", - sbus_readb(&aurora_board[0].r[0]->r[CD180_SRSR]), - sbus_readb(&aurora_board[0].r[1]->r[CD180_SRSR])); - for (i = 0; i < 4; i++) { - udelay(1); - printk("%02x ", - sbus_readb(&aurora_board[0].r3->r[i])); - } - printk("\n"); - - aurora_poll_timer.expires = jiffies + 300; - add_timer (&aurora_poll_timer); - - restore_flags(flags); -} -#endif - -/* - * Routines for open & close processing. - */ - -/* Called with disabled interrupts */ -static int aurora_setup_board(struct Aurora_board * bp) -{ - int error; - -#ifdef AURORA_ALLIRQ - int i; - for (i = 0; i < AURORA_ALLIRQ; i++) { - error = request_irq(allirq[i]|0x30, aurora_interrupt, IRQF_SHARED, - "sio16", bp); - if (error) - printk(KERN_ERR "IRQ%d request error %d\n", - allirq[i], error); - } -#else - error = request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, - "sio16", bp); - if (error) { - printk(KERN_ERR "IRQ request error %d\n", error); - return error; - } -#endif - /* Board reset */ - sbus_writeb(0, &bp->r0->r); - udelay(1); - if (bp->flags & AURORA_BOARD_TYPE_2) { - /* unknown yet */ - } else { - sbus_writeb((AURORA_CFG_ENABLE_IO | AURORA_CFG_ENABLE_IRQ | - (((bp->irq)&0x0f)>>2)), - &bp->r0->r); - } - udelay(10000); - - if (aurora_init_CD180(bp,0))error=1;error=0; - if (aurora_init_CD180(bp,1))error++; - if (error == AURORA_NCD180) { - printk(KERN_ERR "Both chips failed initialisation.\n"); - return -EIO; - } - -#ifdef AURORA_INT_DEBUG - aurora_poll_timer.expires= jiffies + 1; - add_timer(&aurora_poll_timer); -#endif -#ifdef AURORA_DEBUG - printk("aurora_setup_board: end\n"); -#endif - return 0; -} - -/* Called with disabled interrupts */ -static void aurora_shutdown_board(struct Aurora_board *bp) -{ - int i; - -#ifdef AURORA_DEBUG - printk("aurora_shutdown_board: start\n"); -#endif - -#ifdef AURORA_INT_DEBUG - del_timer(&aurora_poll_timer); -#endif - -#ifdef AURORA_ALLIRQ - for(i=0;i<AURORA_ALLIRQ;i++){ - free_irq(allirq[i]|0x30, bp); -/* IRQ_to_board[allirq[i]&0xf] = NULL;*/ - } -#else - free_irq(bp->irq|0x30, bp); -/* IRQ_to_board[bp->irq&0xf] = NULL;*/ -#endif - /* Drop all DTR's */ - for(i=0;i<16;i++){ - sbus_writeb(i & 7, &bp->r[i>>3]->r[CD180_CAR]); - udelay(1); - sbus_writeb(0, &bp->r[i>>3]->r[CD180_MSVR]); - udelay(1); - } - /* Board shutdown */ - sbus_writeb(0, &bp->r0->r); - -#ifdef AURORA_DEBUG - printk("aurora_shutdown_board: end\n"); -#endif -} - -/* Setting up port characteristics. - * Must be called with disabled interrupts - */ -static void aurora_change_speed(struct Aurora_board *bp, struct Aurora_port *port) -{ - struct tty_struct *tty; - unsigned long baud; - long tmp; - unsigned char cor1 = 0, cor3 = 0; - unsigned char mcor1 = 0, mcor2 = 0,chip; - -#ifdef AURORA_DEBUG - printk("aurora_change_speed: start\n"); -#endif - if (!(tty = port->tty) || !tty->termios) - return; - - chip = AURORA_CD180(port_No(port)); - - port->SRER = 0; - port->COR2 = 0; - port->MSVR = MSVR_RTS|MSVR_DTR; - - baud = tty_get_baud_rate(tty); - - /* Select port on the board */ - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - - if (!baud) { - /* Drop DTR & exit */ - port->MSVR &= ~(bp->DTR|bp->RTS); - sbus_writeb(port->MSVR, - &bp->r[chip]->r[CD180_MSVR]); - return; - } else { - /* Set DTR on */ - port->MSVR |= bp->DTR; - sbus_writeb(port->MSVR, - &bp->r[chip]->r[CD180_MSVR]); - } - - /* Now we must calculate some speed dependent things. */ - - /* Set baud rate for port. */ - tmp = (((bp->oscfreq + baud/2) / baud + - CD180_TPC/2) / CD180_TPC); - -/* tmp = (bp->oscfreq/7)/baud; - if((tmp%10)>4)tmp=tmp/10+1;else tmp=tmp/10;*/ -/* printk("Prescaler period: %d\n",tmp);*/ - - sbus_writeb((tmp >> 8) & 0xff, - &bp->r[chip]->r[CD180_RBPRH]); - sbus_writeb((tmp >> 8) & 0xff, - &bp->r[chip]->r[CD180_TBPRH]); - sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_RBPRL]); - sbus_writeb(tmp & 0xff, &bp->r[chip]->r[CD180_TBPRL]); - - baud = (baud + 5) / 10; /* Estimated CPS */ - - /* Two timer ticks seems enough to wakeup something like SLIP driver */ - tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO; - port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ? - SERIAL_XMIT_SIZE - 1 : tmp); - - /* Receiver timeout will be transmission time for 1.5 chars */ - tmp = (AURORA_TPS + AURORA_TPS/2 + baud/2) / baud; - tmp = (tmp > 0xff) ? 0xff : tmp; - sbus_writeb(tmp, &bp->r[chip]->r[CD180_RTPR]); - - switch (C_CSIZE(tty)) { - case CS5: - cor1 |= COR1_5BITS; - break; - case CS6: - cor1 |= COR1_6BITS; - break; - case CS7: - cor1 |= COR1_7BITS; - break; - case CS8: - cor1 |= COR1_8BITS; - break; - } - - if (C_CSTOPB(tty)) - cor1 |= COR1_2SB; - - cor1 |= COR1_IGNORE; - if (C_PARENB(tty)) { - cor1 |= COR1_NORMPAR; - if (C_PARODD(tty)) - cor1 |= COR1_ODDP; - if (I_INPCK(tty)) - cor1 &= ~COR1_IGNORE; - } - /* Set marking of some errors */ - port->mark_mask = RCSR_OE | RCSR_TOUT; - if (I_INPCK(tty)) - port->mark_mask |= RCSR_FE | RCSR_PE; - if (I_BRKINT(tty) || I_PARMRK(tty)) - port->mark_mask |= RCSR_BREAK; - if (I_IGNPAR(tty)) - port->mark_mask &= ~(RCSR_FE | RCSR_PE); - if (I_IGNBRK(tty)) { - port->mark_mask &= ~RCSR_BREAK; - if (I_IGNPAR(tty)) - /* Real raw mode. Ignore all */ - port->mark_mask &= ~RCSR_OE; - } - /* Enable Hardware Flow Control */ - if (C_CRTSCTS(tty)) { -/*#ifdef AURORA_BRAIN_DAMAGED_CTS - port->SRER |= SRER_DSR | SRER_CTS; - mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD; - mcor2 |= MCOR2_DSROD | MCOR2_CTSOD; - tty->hw_stopped = !(aurora_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR)); -#else*/ - port->COR2 |= COR2_CTSAE; -/*#endif*/ - if (bp->flags&AURORA_BOARD_DTR_FLOW_OK) { - mcor1 |= AURORA_RXTH; - } - } - /* Enable Software Flow Control. FIXME: I'm not sure about this */ - /* Some people reported that it works, but I still doubt */ - if (I_IXON(tty)) { - port->COR2 |= COR2_TXIBE; - cor3 |= (COR3_FCT | COR3_SCDE); - if (I_IXANY(tty)) - port->COR2 |= COR2_IXM; - sbus_writeb(START_CHAR(tty), - &bp->r[chip]->r[CD180_SCHR1]); - sbus_writeb(STOP_CHAR(tty), - &bp->r[chip]->r[CD180_SCHR2]); - sbus_writeb(START_CHAR(tty), - &bp->r[chip]->r[CD180_SCHR3]); - sbus_writeb(STOP_CHAR(tty), - &bp->r[chip]->r[CD180_SCHR4]); - } - if (!C_CLOCAL(tty)) { - /* Enable CD check */ - port->SRER |= SRER_CD; - mcor1 |= MCOR1_CDZD; - mcor2 |= MCOR2_CDOD; - } - - if (C_CREAD(tty)) - /* Enable receiver */ - port->SRER |= SRER_RXD; - - /* Set input FIFO size (1-8 bytes) */ - cor3 |= AURORA_RXFIFO; - /* Setting up CD180 channel registers */ - sbus_writeb(cor1, &bp->r[chip]->r[CD180_COR1]); - sbus_writeb(port->COR2, &bp->r[chip]->r[CD180_COR2]); - sbus_writeb(cor3, &bp->r[chip]->r[CD180_COR3]); - /* Make CD180 know about registers change */ - aurora_wait_CCR(bp->r[chip]); - sbus_writeb(CCR_CORCHG1 | CCR_CORCHG2 | CCR_CORCHG3, - &bp->r[chip]->r[CD180_CCR]); - /* Setting up modem option registers */ - sbus_writeb(mcor1, &bp->r[chip]->r[CD180_MCOR1]); - sbus_writeb(mcor2, &bp->r[chip]->r[CD180_MCOR2]); - /* Enable CD180 transmitter & receiver */ - aurora_wait_CCR(bp->r[chip]); - sbus_writeb(CCR_TXEN | CCR_RXEN, &bp->r[chip]->r[CD180_CCR]); - /* Enable interrupts */ - sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]); - /* And finally set RTS on */ - sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]); -#ifdef AURORA_DEBUG - printk("aurora_change_speed: end\n"); -#endif -} - -/* Must be called with interrupts enabled */ -static int aurora_setup_port(struct Aurora_board *bp, struct Aurora_port *port) -{ - unsigned long flags; - -#ifdef AURORA_DEBUG - printk("aurora_setup_port: start %d\n",port_No(port)); -#endif - if (port->flags & ASYNC_INITIALIZED) - return 0; - - if (!port->xmit_buf) { - /* We may sleep in get_zeroed_page() */ - unsigned long tmp; - - if (!(tmp = get_zeroed_page(GFP_KERNEL))) - return -ENOMEM; - - if (port->xmit_buf) { - free_page(tmp); - return -ERESTARTSYS; - } - port->xmit_buf = (unsigned char *) tmp; - } - - save_flags(flags); cli(); - - if (port->tty) - clear_bit(TTY_IO_ERROR, &port->tty->flags); - -#ifdef MODULE - if ((port->count == 1) && ((++bp->count) == 1)) - bp->flags |= AURORA_BOARD_ACTIVE; -#endif - - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - aurora_change_speed(bp, port); - port->flags |= ASYNC_INITIALIZED; - - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_setup_port: end\n"); -#endif - return 0; -} - -/* Must be called with interrupts disabled */ -static void aurora_shutdown_port(struct Aurora_board *bp, struct Aurora_port *port) -{ - struct tty_struct *tty; - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("aurora_shutdown_port: start\n"); -#endif - if (!(port->flags & ASYNC_INITIALIZED)) - return; - - chip = AURORA_CD180(port_No(port)); - -#ifdef AURORA_REPORT_OVERRUN - printk("aurora%d: port %d: Total %ld overruns were detected.\n", - board_No(bp), port_No(port), port->overrun); -#endif -#ifdef AURORA_REPORT_FIFO - { - int i; - - printk("aurora%d: port %d: FIFO hits [ ", - board_No(bp), port_No(port)); - for (i = 0; i < 10; i++) { - printk("%ld ", port->hits[i]); - } - printk("].\n"); - } -#endif - if (port->xmit_buf) { - free_page((unsigned long) port->xmit_buf); - port->xmit_buf = NULL; - } - - if (!(tty = port->tty) || C_HUPCL(tty)) { - /* Drop DTR */ - port->MSVR &= ~(bp->DTR|bp->RTS); - sbus_writeb(port->MSVR, - &bp->r[chip]->r[CD180_MSVR]); - } - - /* Select port */ - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - - /* Reset port */ - aurora_wait_CCR(bp->r[chip]); - sbus_writeb(CCR_SOFTRESET, &bp->r[chip]->r[CD180_CCR]); - - /* Disable all interrupts from this port */ - port->SRER = 0; - sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]); - - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); - port->flags &= ~ASYNC_INITIALIZED; - -#ifdef MODULE - if (--bp->count < 0) { - printk(KERN_DEBUG "aurora%d: aurora_shutdown_port: " - "bad board count: %d\n", - board_No(bp), bp->count); - bp->count = 0; - } - - if (!bp->count) - bp->flags &= ~AURORA_BOARD_ACTIVE; -#endif - -#ifdef AURORA_DEBUG - printk("aurora_shutdown_port: end\n"); -#endif -} - - -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct Aurora_port *port) -{ - DECLARE_WAITQUEUE(wait, current); - struct Aurora_board *bp = port_Board(port); - int retval; - int do_clocal = 0; - int CD; - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("block_til_ready: start\n"); -#endif - chip = AURORA_CD180(port_No(port)); - - /* If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - interruptible_sleep_on(&port->close_wait); - if (port->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; - } - - /* If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - port->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (C_CLOCAL(tty)) - do_clocal = 1; - - /* Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&port->open_wait, &wait); - cli(); - if (!tty_hung_up_p(filp)) - port->count--; - sti(); - port->blocked_open++; - while (1) { - cli(); - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - CD = sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD; - port->MSVR=bp->RTS; - - /* auto drops DTR */ - sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]); - sti(); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(port->flags & ASYNC_INITIALIZED)) { - if (port->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; - break; - } - if (!(port->flags & ASYNC_CLOSING) && - (do_clocal || CD)) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&port->open_wait, &wait); - if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; - if (retval) - return retval; - - port->flags |= ASYNC_NORMAL_ACTIVE; -#ifdef AURORA_DEBUG - printk("block_til_ready: end\n"); -#endif - return 0; -} - -static int aurora_open(struct tty_struct * tty, struct file * filp) -{ - int board; - int error; - struct Aurora_port * port; - struct Aurora_board * bp; - unsigned long flags; - -#ifdef AURORA_DEBUG - printk("aurora_open: start\n"); -#endif - - board = AURORA_BOARD(tty->index); - if (board > AURORA_NBOARD || - !(aurora_board[board].flags & AURORA_BOARD_PRESENT)) { -#ifdef AURORA_DEBUG - printk("aurora_open: error board %d present %d\n", - board, aurora_board[board].flags & AURORA_BOARD_PRESENT); -#endif - return -ENODEV; - } - - bp = &aurora_board[board]; - port = aurora_port + board * AURORA_NPORT * AURORA_NCD180 + AURORA_PORT(tty->index); - if ((aurora_paranoia_check(port, tty->name, "aurora_open")) { -#ifdef AURORA_DEBUG - printk("aurora_open: error paranoia check\n"); -#endif - return -ENODEV; - } - - port->count++; - tty->driver_data = port; - port->tty = tty; - - if ((error = aurora_setup_port(bp, port))) { -#ifdef AURORA_DEBUG - printk("aurora_open: error aurora_setup_port ret %d\n",error); -#endif - return error; - } - - if ((error = block_til_ready(tty, filp, port))) { -#ifdef AURORA_DEBUG - printk("aurora_open: error block_til_ready ret %d\n",error); -#endif - return error; - } - -#ifdef AURORA_DEBUG - printk("aurora_open: end\n"); -#endif - return 0; -} - -static void aurora_close(struct tty_struct * tty, struct file * filp) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - struct Aurora_board *bp; - unsigned long flags; - unsigned long timeout; - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("aurora_close: start\n"); -#endif - - if (!port || (aurora_paranoia_check(port, tty->name, "close")) - return; - - chip = AURORA_CD180(port_No(port)); - - save_flags(flags); cli(); - if (tty_hung_up_p(filp)) { - restore_flags(flags); - return; - } - - bp = port_Board(port); - if ((tty->count == 1) && (port->count != 1)) { - printk(KERN_DEBUG "aurora%d: aurora_close: bad port count; " - "tty->count is 1, port count is %d\n", - board_No(bp), port->count); - port->count = 1; - } - if (--port->count < 0) { - printk(KERN_DEBUG "aurora%d: aurora_close: bad port " - "count for tty%d: %d\n", - board_No(bp), port_No(port), port->count); - port->count = 0; - } - if (port->count) { - restore_flags(flags); - return; - } - port->flags |= ASYNC_CLOSING; - - /* Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE){ -#ifdef AURORA_DEBUG - printk("aurora_close: waiting to flush...\n"); -#endif - tty_wait_until_sent(tty, port->closing_wait); - } - - /* At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - port->SRER &= ~SRER_RXD; - if (port->flags & ASYNC_INITIALIZED) { - port->SRER &= ~SRER_TXRDY; - port->SRER |= SRER_TXEMPTY; - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]); - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - timeout = jiffies+HZ; - while(port->SRER & SRER_TXEMPTY) { - msleep_interruptible(jiffies_to_msecs(port->timeout)); - if (time_after(jiffies, timeout)) - break; - } - } -#ifdef AURORA_DEBUG - printk("aurora_close: shutdown_port\n"); -#endif - aurora_shutdown_port(bp, port); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - tty_ldisc_flush(tty); - tty->closing = 0; - port->event = 0; - port->tty = 0; - if (port->blocked_open) { - if (port->close_delay) { - msleep_interruptible(jiffies_to_msecs(port->close_delay)); - } - wake_up_interruptible(&port->open_wait); - } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&port->close_wait); - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_close: end\n"); -#endif -} - -static int aurora_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - struct Aurora_board *bp; - int c, total = 0; - unsigned long flags; - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("aurora_write: start %d\n",count); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_write")) - return 0; - - chip = AURORA_CD180(port_No(port)); - - bp = port_Board(port); - - if (!tty || !port->xmit_buf || !tmp_buf) - return 0; - - save_flags(flags); - while (1) { - cli(); - c = min(count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, - SERIAL_XMIT_SIZE - port->xmit_head)); - if (c <= 0) { - restore_flags(flags); - break; - } - memcpy(port->xmit_buf + port->xmit_head, buf, c); - port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); - port->xmit_cnt += c; - restore_flags(flags); - - buf += c; - count -= c; - total += c; - } - - cli(); - if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && - !(port->SRER & SRER_TXRDY)) { - port->SRER |= SRER_TXRDY; - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]); - } - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_write: end %d\n",total); -#endif - return total; -} - -static void aurora_put_char(struct tty_struct * tty, unsigned char ch) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - unsigned long flags; - -#ifdef AURORA_DEBUG - printk("aurora_put_char: start %c\n",ch); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_put_char")) - return; - - if (!tty || !port->xmit_buf) - return; - - save_flags(flags); cli(); - - if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { - restore_flags(flags); - return; - } - - port->xmit_buf[port->xmit_head++] = ch; - port->xmit_head &= SERIAL_XMIT_SIZE - 1; - port->xmit_cnt++; - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_put_char: end\n"); -#endif -} - -static void aurora_flush_chars(struct tty_struct * tty) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - unsigned long flags; - unsigned char chip; - -/*#ifdef AURORA_DEBUG - printk("aurora_flush_chars: start\n"); -#endif*/ - if ((aurora_paranoia_check(port, tty->name, "aurora_flush_chars")) - return; - - chip = AURORA_CD180(port_No(port)); - - if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !port->xmit_buf) - return; - - save_flags(flags); cli(); - port->SRER |= SRER_TXRDY; - sbus_writeb(port_No(port) & 7, - &port_Board(port)->r[chip]->r[CD180_CAR]); - udelay(1); - sbus_writeb(port->SRER, - &port_Board(port)->r[chip]->r[CD180_SRER]); - restore_flags(flags); -/*#ifdef AURORA_DEBUG - printk("aurora_flush_chars: end\n"); -#endif*/ -} - -static int aurora_write_room(struct tty_struct * tty) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - int ret; - -#ifdef AURORA_DEBUG - printk("aurora_write_room: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_write_room")) - return 0; - - ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; - if (ret < 0) - ret = 0; -#ifdef AURORA_DEBUG - printk("aurora_write_room: end\n"); -#endif - return ret; -} - -static int aurora_chars_in_buffer(struct tty_struct *tty) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - - if ((aurora_paranoia_check(port, tty->name, "aurora_chars_in_buffer")) - return 0; - - return port->xmit_cnt; -} - -static void aurora_flush_buffer(struct tty_struct *tty) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - unsigned long flags; - -#ifdef AURORA_DEBUG - printk("aurora_flush_buffer: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_flush_buffer")) - return; - - save_flags(flags); cli(); - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - restore_flags(flags); - - tty_wakeup(tty); -#ifdef AURORA_DEBUG - printk("aurora_flush_buffer: end\n"); -#endif -} - -static int aurora_tiocmget(struct tty_struct *tty, struct file *file) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - struct Aurora_board * bp; - unsigned char status,chip; - unsigned int result; - unsigned long flags; - -#ifdef AURORA_DEBUG - printk("aurora_get_modem_info: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, __FUNCTION__)) - return -ENODEV; - - chip = AURORA_CD180(port_No(port)); - - bp = port_Board(port); - - save_flags(flags); cli(); - - sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]); - udelay(1); - - status = sbus_readb(&bp->r[chip]->r[CD180_MSVR]); - result = 0/*bp->r[chip]->r[AURORA_RI] & (1u << port_No(port)) ? 0 : TIOCM_RNG*/; - - restore_flags(flags); - - result |= ((status & bp->RTS) ? TIOCM_RTS : 0) - | ((status & bp->DTR) ? TIOCM_DTR : 0) - | ((status & MSVR_CD) ? TIOCM_CAR : 0) - | ((status & MSVR_DSR) ? TIOCM_DSR : 0) - | ((status & MSVR_CTS) ? TIOCM_CTS : 0); - -#ifdef AURORA_DEBUG - printk("aurora_get_modem_info: end\n"); -#endif - return result; -} - -static int aurora_tiocmset(struct tty_struct *tty, struct file *file, - unsigned int set, unsigned int clear) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - unsigned int arg; - unsigned long flags; - struct Aurora_board *bp = port_Board(port); - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("aurora_set_modem_info: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, __FUNCTION__)) - return -ENODEV; - - chip = AURORA_CD180(port_No(port)); - - save_flags(flags); cli(); - if (set & TIOCM_RTS) - port->MSVR |= bp->RTS; - if (set & TIOCM_DTR) - port->MSVR |= bp->DTR; - if (clear & TIOCM_RTS) - port->MSVR &= ~bp->RTS; - if (clear & TIOCM_DTR) - port->MSVR &= ~bp->DTR; - - sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]); - udelay(1); - - sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]); - - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_set_modem_info: end\n"); -#endif - return 0; -} - -static void aurora_send_break(struct Aurora_port * port, unsigned long length) -{ - struct Aurora_board *bp = port_Board(port); - unsigned long flags; - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("aurora_send_break: start\n"); -#endif - chip = AURORA_CD180(port_No(port)); - - save_flags(flags); cli(); - - port->break_length = AURORA_TPS / HZ * length; - port->COR2 |= COR2_ETC; - port->SRER |= SRER_TXRDY; - sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]); - udelay(1); - - sbus_writeb(port->COR2, &bp->r[chip]->r[CD180_COR2]); - sbus_writeb(port->SRER, &bp->r[chip]->r[CD180_SRER]); - aurora_wait_CCR(bp->r[chip]); - - sbus_writeb(CCR_CORCHG2, &bp->r[chip]->r[CD180_CCR]); - aurora_wait_CCR(bp->r[chip]); - - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_send_break: end\n"); -#endif -} - -static int aurora_set_serial_info(struct Aurora_port * port, - struct serial_struct * newinfo) -{ - struct serial_struct tmp; - struct Aurora_board *bp = port_Board(port); - int change_speed; - unsigned long flags; - -#ifdef AURORA_DEBUG - printk("aurora_set_serial_info: start\n"); -#endif - if (copy_from_user(&tmp, newinfo, sizeof(tmp))) - return -EFAULT; -#if 0 - if ((tmp.irq != bp->irq) || - (tmp.port != bp->base) || - (tmp.type != PORT_CIRRUS) || - (tmp.baud_base != (bp->oscfreq + CD180_TPC/2) / CD180_TPC) || - (tmp.custom_divisor != 0) || - (tmp.xmit_fifo_size != CD180_NFIFO) || - (tmp.flags & ~AURORA_LEGAL_FLAGS)) - return -EINVAL; -#endif - - change_speed = ((port->flags & ASYNC_SPD_MASK) != - (tmp.flags & ASYNC_SPD_MASK)); - - if (!capable(CAP_SYS_ADMIN)) { - if ((tmp.close_delay != port->close_delay) || - (tmp.closing_wait != port->closing_wait) || - ((tmp.flags & ~ASYNC_USR_MASK) != - (port->flags & ~ASYNC_USR_MASK))) - return -EPERM; - port->flags = ((port->flags & ~ASYNC_USR_MASK) | - (tmp.flags & ASYNC_USR_MASK)); - } else { - port->flags = ((port->flags & ~ASYNC_FLAGS) | - (tmp.flags & ASYNC_FLAGS)); - port->close_delay = tmp.close_delay; - port->closing_wait = tmp.closing_wait; - } - if (change_speed) { - save_flags(flags); cli(); - aurora_change_speed(bp, port); - restore_flags(flags); - } -#ifdef AURORA_DEBUG - printk("aurora_set_serial_info: end\n"); -#endif - return 0; -} - -extern int aurora_get_serial_info(struct Aurora_port * port, - struct serial_struct * retinfo) -{ - struct serial_struct tmp; - struct Aurora_board *bp = port_Board(port); - -#ifdef AURORA_DEBUG - printk("aurora_get_serial_info: start\n"); -#endif - if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp))) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - tmp.type = PORT_CIRRUS; - tmp.line = port - aurora_port; - tmp.port = 0; - tmp.irq = bp->irq; - tmp.flags = port->flags; - tmp.baud_base = (bp->oscfreq + CD180_TPC/2) / CD180_TPC; - tmp.close_delay = port->close_delay * HZ/100; - tmp.closing_wait = port->closing_wait * HZ/100; - tmp.xmit_fifo_size = CD180_NFIFO; - copy_to_user(retinfo, &tmp, sizeof(tmp)); -#ifdef AURORA_DEBUG -printk("aurora_get_serial_info: end\n"); -#endif - return 0; -} - -static int aurora_ioctl(struct tty_struct * tty, struct file * filp, - unsigned int cmd, unsigned long arg) - -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - int retval; - -#ifdef AURORA_DEBUG - printk("aurora_ioctl: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_ioctl")) - return -ENODEV; - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (!arg) - aurora_send_break(port, HZ/4); /* 1/4 second */ - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - aurora_send_break(port, arg ? arg*(HZ/10) : HZ/4); - return 0; - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); - case TIOCSSOFTCAR: - if (get_user(arg,(unsigned long *)arg)) - return -EFAULT; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; - case TIOCGSERIAL: - return aurora_get_serial_info(port, (struct serial_struct *) arg); - case TIOCSSERIAL: - return aurora_set_serial_info(port, (struct serial_struct *) arg); - default: - return -ENOIOCTLCMD; - }; -#ifdef AURORA_DEBUG - printk("aurora_ioctl: end\n"); -#endif - return 0; -} - -static void aurora_throttle(struct tty_struct * tty) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - struct Aurora_board *bp; - unsigned long flags; - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("aurora_throttle: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_throttle")) - return; - - bp = port_Board(port); - chip = AURORA_CD180(port_No(port)); - - save_flags(flags); cli(); - port->MSVR &= ~bp->RTS; - sbus_writeb(port_No(port) & 7, &bp->r[chip]->r[CD180_CAR]); - udelay(1); - if (I_IXOFF(tty)) { - aurora_wait_CCR(bp->r[chip]); - sbus_writeb(CCR_SSCH2, &bp->r[chip]->r[CD180_CCR]); - aurora_wait_CCR(bp->r[chip]); - } - sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]); - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_throttle: end\n"); -#endif -} - -static void aurora_unthrottle(struct tty_struct * tty) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - struct Aurora_board *bp; - unsigned long flags; - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("aurora_unthrottle: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_unthrottle")) - return; - - bp = port_Board(port); - - chip = AURORA_CD180(port_No(port)); - - save_flags(flags); cli(); - port->MSVR |= bp->RTS; - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - if (I_IXOFF(tty)) { - aurora_wait_CCR(bp->r[chip]); - sbus_writeb(CCR_SSCH1, - &bp->r[chip]->r[CD180_CCR]); - aurora_wait_CCR(bp->r[chip]); - } - sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]); - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_unthrottle: end\n"); -#endif -} - -static void aurora_stop(struct tty_struct * tty) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - struct Aurora_board *bp; - unsigned long flags; - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("aurora_stop: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_stop")) - return; - - bp = port_Board(port); - - chip = AURORA_CD180(port_No(port)); - - save_flags(flags); cli(); - port->SRER &= ~SRER_TXRDY; - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - sbus_writeb(port->SRER, - &bp->r[chip]->r[CD180_SRER]); - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_stop: end\n"); -#endif -} - -static void aurora_start(struct tty_struct * tty) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - struct Aurora_board *bp; - unsigned long flags; - unsigned char chip; - -#ifdef AURORA_DEBUG - printk("aurora_start: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_start")) - return; - - bp = port_Board(port); - - chip = AURORA_CD180(port_No(port)); - - save_flags(flags); cli(); - if (port->xmit_cnt && port->xmit_buf && !(port->SRER & SRER_TXRDY)) { - port->SRER |= SRER_TXRDY; - sbus_writeb(port_No(port) & 7, - &bp->r[chip]->r[CD180_CAR]); - udelay(1); - sbus_writeb(port->SRER, - &bp->r[chip]->r[CD180_SRER]); - } - restore_flags(flags); -#ifdef AURORA_DEBUG - printk("aurora_start: end\n"); -#endif -} - -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_aurora_hangup() -> tty->hangup() -> aurora_hangup() - * - */ -static void do_aurora_hangup(void *private_) -{ - struct Aurora_port *port = (struct Aurora_port *) private_; - struct tty_struct *tty; - -#ifdef AURORA_DEBUG - printk("do_aurora_hangup: start\n"); -#endif - tty = port->tty; - if (tty != NULL) { - tty_hangup(tty); /* FIXME: module removal race - AKPM */ -#ifdef AURORA_DEBUG - printk("do_aurora_hangup: end\n"); -#endif - } -} - -static void aurora_hangup(struct tty_struct * tty) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - struct Aurora_board *bp; - -#ifdef AURORA_DEBUG - printk("aurora_hangup: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_hangup")) - return; - - bp = port_Board(port); - - aurora_shutdown_port(bp, port); - port->event = 0; - port->count = 0; - port->flags &= ~ASYNC_NORMAL_ACTIVE; - port->tty = 0; - wake_up_interruptible(&port->open_wait); -#ifdef AURORA_DEBUG - printk("aurora_hangup: end\n"); -#endif -} - -static void aurora_set_termios(struct tty_struct * tty, struct termios * old_termios) -{ - struct Aurora_port *port = (struct Aurora_port *) tty->driver_data; - unsigned long flags; - -#ifdef AURORA_DEBUG - printk("aurora_set_termios: start\n"); -#endif - if ((aurora_paranoia_check(port, tty->name, "aurora_set_termios")) - return; - - if (tty->termios->c_cflag == old_termios->c_cflag && - tty->termios->c_iflag == old_termios->c_iflag) - return; - - save_flags(flags); cli(); - aurora_change_speed(port_Board(port), port); - restore_flags(flags); - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - aurora_start(tty); - } -#ifdef AURORA_DEBUG - printk("aurora_set_termios: end\n"); -#endif -} - -static void do_aurora_bh(void) -{ - run_task_queue(&tq_aurora); -} - -static void do_softint(void *private_) -{ - struct Aurora_port *port = (struct Aurora_port *) private_; - struct tty_struct *tty; - -#ifdef AURORA_DEBUG - printk("do_softint: start\n"); -#endif - tty = port->tty; - if (tty == NULL) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) { - tty_wakeup(tty); - } -#ifdef AURORA_DEBUG - printk("do_softint: end\n"); -#endif -} - -static const struct tty_operations aurora_ops = { - .open = aurora_open, - .close = aurora_close, - .write = aurora_write, - .put_char = aurora_put_char, - .flush_chars = aurora_flush_chars, - .write_room = aurora_write_room, - .chars_in_buffer = aurora_chars_in_buffer, - .flush_buffer = aurora_flush_buffer, - .ioctl = aurora_ioctl, - .throttle = aurora_throttle, - .unthrottle = aurora_unthrottle, - .set_termios = aurora_set_termios, - .stop = aurora_stop, - .start = aurora_start, - .hangup = aurora_hangup, - .tiocmget = aurora_tiocmget, - .tiocmset = aurora_tiocmset, -}; - -static int aurora_init_drivers(void) -{ - int error; - int i; - -#ifdef AURORA_DEBUG - printk("aurora_init_drivers: start\n"); -#endif - tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL); - if (tmp_buf == NULL) { - printk(KERN_ERR "aurora: Couldn't get free page.\n"); - return 1; - } - init_bh(AURORA_BH, do_aurora_bh); - aurora_driver = alloc_tty_driver(AURORA_INPORTS); - if (!aurora_driver) { - printk(KERN_ERR "aurora: Couldn't allocate tty driver.\n"); - free_page((unsigned long) tmp_buf); - return 1; - } - aurora_driver->owner = THIS_MODULE; - aurora_driver->name = "ttyA"; - aurora_driver->major = AURORA_MAJOR; - aurora_driver->type = TTY_DRIVER_TYPE_SERIAL; - aurora_driver->subtype = SERIAL_TYPE_NORMAL; - aurora_driver->init_termios = tty_std_termios; - aurora_driver->init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - aurora_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(aurora_driver, &aurora_ops); - error = tty_register_driver(aurora_driver); - if (error) { - put_tty_driver(aurora_driver); - free_page((unsigned long) tmp_buf); - printk(KERN_ERR "aurora: Couldn't register aurora driver, error = %d\n", - error); - return 1; - } - - memset(aurora_port, 0, sizeof(aurora_port)); - for (i = 0; i < AURORA_TNPORTS; i++) { - aurora_port[i].magic = AURORA_MAGIC; - aurora_port[i].tqueue.routine = do_softint; - aurora_port[i].tqueue.data = &aurora_port[i]; - aurora_port[i].tqueue_hangup.routine = do_aurora_hangup; - aurora_port[i].tqueue_hangup.data = &aurora_port[i]; - aurora_port[i].close_delay = 50 * HZ/100; - aurora_port[i].closing_wait = 3000 * HZ/100; - init_waitqueue_head(&aurora_port[i].open_wait); - init_waitqueue_head(&aurora_port[i].close_wait); - } -#ifdef AURORA_DEBUG - printk("aurora_init_drivers: end\n"); -#endif - return 0; -} - -static void aurora_release_drivers(void) -{ -#ifdef AURORA_DEBUG - printk("aurora_release_drivers: start\n"); -#endif - free_page((unsigned long)tmp_buf); - tty_unregister_driver(aurora_driver); - put_tty_driver(aurora_driver); -#ifdef AURORA_DEBUG - printk("aurora_release_drivers: end\n"); -#endif -} - -/* - * Called at boot time. - * - * You can specify IO base for up to RC_NBOARD cards, - * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt. - * Note that there will be no probing at default - * addresses in this case. - * - */ -void __init aurora_setup(char *str, int *ints) -{ - int i; - - for(i=0;(i<ints[0])&&(i<4);i++) { - if (ints[i+1]) irqs[i]=ints[i+1]; - } -} - -static int __init aurora_real_init(void) -{ - int found; - int i; - - printk(KERN_INFO "aurora: Driver starting.\n"); - if(aurora_init_drivers()) - return -EIO; - found = aurora_probe(); - if(!found) { - aurora_release_drivers(); - printk(KERN_INFO "aurora: No Aurora Multiport boards detected.\n"); - return -EIO; - } else { - printk(KERN_INFO "aurora: %d boards found.\n", found); - } - for (i = 0; i < found; i++) { - int ret = aurora_setup_board(&aurora_board[i]); - - if (ret) { -#ifdef AURORA_DEBUG - printk(KERN_ERR "aurora_init: error aurora_setup_board ret %d\n", - ret); -#endif - return ret; - } - } - return 0; -} - -int irq = 0; -int irq1 = 0; -int irq2 = 0; -int irq3 = 0; -module_param(irq , int, 0); -module_param(irq1, int, 0); -module_param(irq2, int, 0); -module_param(irq3, int, 0); - -static int __init aurora_init(void) -{ - if (irq ) irqs[0]=irq ; - if (irq1) irqs[1]=irq1; - if (irq2) irqs[2]=irq2; - if (irq3) irqs[3]=irq3; - return aurora_real_init(); -} - -static void __exit aurora_cleanup(void) -{ - int i; - -#ifdef AURORA_DEBUG -printk("cleanup_module: aurora_release_drivers\n"); -#endif - - aurora_release_drivers(); - for (i = 0; i < AURORA_NBOARD; i++) - if (aurora_board[i].flags & AURORA_BOARD_PRESENT) { - aurora_shutdown_board(&aurora_board[i]); - aurora_release_io_range(&aurora_board[i]); - } -} - -module_init(aurora_init); -module_exit(aurora_cleanup); -MODULE_LICENSE("GPL"); diff --git a/drivers/sbus/char/aurora.h b/drivers/sbus/char/aurora.h deleted file mode 100644 index b8b5476d986..00000000000 --- a/drivers/sbus/char/aurora.h +++ /dev/null @@ -1,276 +0,0 @@ -/* $Id: aurora.h,v 1.6 2001/06/05 12:23:38 davem Exp $ - * linux/drivers/sbus/char/aurora.h -- Aurora multiport driver - * - * Copyright (c) 1999 by Oliver Aldulea (oli@bv.ro) - * - * This code is based on the RISCom/8 multiport serial driver written - * by Dmitry Gorodchanin (pgmdsg@ibi.com), based on the Linux serial - * driver, written by Linus Torvalds, Theodore T'so and others. - * The Aurora multiport programming info was obtained mainly from the - * Cirrus Logic CD180 documentation (available on the web), and by - * doing heavy tests on the board. Many thanks to Eddie C. Dost for the - * help on the sbus interface. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Revision 1.0 - * - * This is the first public release. - * - * This version needs a lot of feedback. This is the version that works - * with _my_ board. My board is model 1600se, revision '@(#)1600se.fth - * 1.2 3/28/95 1'. The driver might work with your board, but I do not - * guarantee it. If you have _any_ type of board, I need to know if the - * driver works or not, I need to know exactly your board parameters - * (get them with 'cd /proc/openprom/iommu/sbus/sio16/; ls *; cat *') - * Also, I need your board revision code, which is written on the board. - * Send me the output of my driver too (it outputs through klogd). - * - * If the driver does not work, you can try enabling the debug options - * to see what's wrong or what should be done. - * - * I'm sorry about the alignment of the code. It was written in a - * 128x48 environment. - * - * I must say that I do not like Aurora Technologies' policy. I asked - * them to help me do this driver faster, but they ended by something - * like "don't call us, we'll call you", and I never heard anything - * from them. They told me "knowing the way the board works, I don't - * doubt you and others on the net will make the driver." - * The truth about this board is that it has nothing intelligent on it. - * If you want to say to somebody what kind of board you have, say that - * it uses Cirrus Logic processors (CD180). The power of the board is - * in those two chips. The rest of the board is the interface to the - * sbus and to the peripherals. Still, they did something smart: they - * reversed DTR and RTS to make on-board automatic hardware flow - * control usable. - * Thanks to Aurora Technologies for wasting my time, nerves and money. - */ - -#ifndef __LINUX_AURORA_H -#define __LINUX_AURORA_H - -#include <linux/serial.h> -#include <linux/serialP.h> - -#ifdef __KERNEL__ - -/* This is the number of boards to support. I've only tested this driver with - * one board, so it might not work. - */ -#define AURORA_NBOARD 1 - -/* Useful ? Yes. But you can safely comment the warnings if they annoy you - * (let me say that again: the warnings in the code, not this define). - */ -#define AURORA_PARANOIA_CHECK - -/* Well, after many lost nights, I found that the IRQ for this board is - * selected from four built-in values by writing some bits in the - * configuration register. This causes a little problem to occur: which - * IRQ to select ? Which one is the best for the user ? Well, I finally - * decided for the following algorithm: if the "bintr" value is not acceptable - * (not within type_1_irq[], then test the "intr" value, if that fails too, - * try each value from type_1_irq until succeded. Hope it's ok. - * You can safely reorder the irq's. - */ -#define TYPE_1_IRQS 4 -unsigned char type_1_irq[TYPE_1_IRQS] = { - 3, 5, 9, 13 -}; -/* I know something about another method of interrupt setting, but not enough. - * Also, this is for another type of board, so I first have to learn how to - * detect it. -#define TYPE_2_IRQS 3 -unsigned char type_2_irq[TYPE_2_IRQS] = { - 0, 0, 0 ** could anyone find these for me ? (see AURORA_ALLIRQ below) ** - }; -unsigned char type_2_mask[TYPE_2_IRQS] = { - 32, 64, 128 - }; -*/ - -/* The following section should only be modified by those who know what - * they're doing (or don't, but want to help with some feedback). Modifying - * anything raises a _big_ probability for your system to hang, but the - * sacrifice worths. (I sacrificed my ext2fs many, many times...) - */ - -/* This one tries to dump to console the name of almost every function called, - * and many other debugging info. - */ -#undef AURORA_DEBUG - -/* These are the most dangerous and useful defines. They do printk() during - * the interrupt processing routine(s), so if you manage to get "flooded" by - * irq's, start thinking about the "Power off/on" button... - */ -#undef AURORA_INTNORM /* This one enables the "normal" messages, but some - * of them cause flood, so I preffered putting - * them under a define */ -#undef AURORA_INT_DEBUG /* This one is really bad. */ - -/* Here's something helpful: after n irq's, the board will be disabled. This - * prevents irq flooding during debug (no need to think about power - * off/on anymore...) - */ -#define AURORA_FLOODPRO 10 - -/* This one helps finding which irq the board calls, in case of a strange/ - * unsupported board. AURORA_INT_DEBUG should be enabled, because I don't - * think /proc/interrupts or any command will be available in case of an irq - * flood... "allirq" is the list of all free irq's. - */ -/* -#define AURORA_ALLIRQ 6 -int allirq[AURORA_ALLIRQ]={ - 2,3,5,7,9,13 - }; -*/ - -/* These must not be modified. These values are assumed during the code for - * performance optimisations. - */ -#define AURORA_NCD180 2 /* two chips per board */ -#define AURORA_NPORT 8 /* 8 ports per chip */ - -/* several utilities */ -#define AURORA_BOARD(line) (((line) >> 4) & 0x01) -#define AURORA_CD180(line) (((line) >> 3) & 0x01) -#define AURORA_PORT(line) ((line) & 15) - -#define AURORA_TNPORTS (AURORA_NBOARD*AURORA_NCD180*AURORA_NPORT) - -/* Ticks per sec. Used for setting receiver timeout and break length */ -#define AURORA_TPS 4000 - -#define AURORA_MAGIC 0x0A18 - -/* Yeah, after heavy testing I decided it must be 6. - * Sure, You can change it if needed. - */ -#define AURORA_RXFIFO 6 /* Max. receiver FIFO size (1-8) */ - -#define AURORA_RXTH 7 - -struct aurora_reg1 { - __volatile__ unsigned char r; -}; - -struct aurora_reg128 { - __volatile__ unsigned char r[128]; -}; - -struct aurora_reg4 { - __volatile__ unsigned char r[4]; -}; - -struct Aurora_board { - unsigned long flags; - struct aurora_reg1 * r0; /* This is the board configuration - * register (write-only). */ - struct aurora_reg128 * r[2]; /* These are the registers for the - * two chips. */ - struct aurora_reg4 * r3; /* These are used for hardware-based - * acknowledge. Software-based ack is - * not supported by CD180. */ - unsigned int oscfreq; /* The on-board oscillator - * frequency, in Hz. */ - unsigned char irq; -#ifdef MODULE - signed char count; /* counts the use of the board */ -#endif - /* Values for the dtr_rts swapped mode. */ - unsigned char DTR; - unsigned char RTS; - unsigned char MSVDTR; - unsigned char MSVRTS; - /* Values for hardware acknowledge. */ - unsigned char ACK_MINT, ACK_TINT, ACK_RINT; -}; - -/* Board configuration register */ -#define AURORA_CFG_ENABLE_IO 8 -#define AURORA_CFG_ENABLE_IRQ 4 - -/* Board flags */ -#define AURORA_BOARD_PRESENT 0x00000001 -#define AURORA_BOARD_ACTIVE 0x00000002 -#define AURORA_BOARD_TYPE_2 0x00000004 /* don't know how to - * detect this yet */ -#define AURORA_BOARD_DTR_FLOW_OK 0x00000008 - -/* The story goes like this: Cirrus programmed the CD-180 chip to do automatic - * hardware flow control, and do it using CTS and DTR. CTS is ok, but, if you - * have a modem and the chip drops DTR, then the modem will drop the carrier - * (ain't that cute...). Luckily, the guys at Aurora decided to swap DTR and - * RTS, which makes the flow control usable. I hope that all the boards made - * by Aurora have these two signals swapped. If your's doesn't but you have a - * breakout box, you can try to reverse them yourself, then set the following - * flag. - */ -#undef AURORA_FORCE_DTR_FLOW - -/* In fact, a few more words have to be said about hardware flow control. - * This driver handles "output" flow control through the on-board facility - * CTS Auto Enable. For the "input" flow control there are two cases when - * the flow should be controlled. The first case is when the kernel is so - * busy that it cannot process IRQ's in time; this flow control can only be - * activated by the on-board chip, and if the board has RTS and DTR swapped, - * this facility is usable. The second case is when the application is so - * busy that it cannot receive bytes from the kernel, and this flow must be - * activated by software. This second case is not yet implemented in this - * driver. Unfortunately, I estimate that the second case is the one that - * occurs the most. - */ - - -struct Aurora_port { - int magic; - int baud_base; - int flags; - struct tty_struct * tty; - int count; - int blocked_open; - long event; - int timeout; - int close_delay; - unsigned char * xmit_buf; - int custom_divisor; - int xmit_head; - int xmit_tail; - int xmit_cnt; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - struct tq_struct tqueue; - struct tq_struct tqueue_hangup; - short wakeup_chars; - short break_length; - unsigned short closing_wait; - unsigned char mark_mask; - unsigned char SRER; - unsigned char MSVR; - unsigned char COR2; -#ifdef AURORA_REPORT_OVERRUN - unsigned long overrun; -#endif -#ifdef AURORA_REPORT_FIFO - unsigned long hits[10]; -#endif -}; - -#endif -#endif /*__LINUX_AURORA_H*/ - diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 22631f8b9b4..8410587348f 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -187,19 +187,20 @@ static int wait_for_pin(struct bbc_i2c_bus *bp, u8 *status) bp->waiting = 1; add_wait_queue(&bp->wq, &wait); while (limit-- > 0) { - u8 val; - - set_current_state(TASK_INTERRUPTIBLE); - *status = val = readb(bp->i2c_control_regs + 0); - if ((val & I2C_PCF_PIN) == 0) { + unsigned long val; + + val = wait_event_interruptible_timeout( + bp->wq, + (((*status = readb(bp->i2c_control_regs + 0)) + & I2C_PCF_PIN) == 0), + msecs_to_jiffies(250)); + if (val > 0) { ret = 0; break; } - msleep_interruptible(250); } remove_wait_queue(&bp->wq, &wait); bp->waiting = 0; - current->state = TASK_RUNNING; return ret; } @@ -340,7 +341,7 @@ static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id) */ if (bp->waiting && !(readb(bp->i2c_control_regs + 0x0) & I2C_PCF_PIN)) - wake_up(&bp->wq); + wake_up_interruptible(&bp->wq); return IRQ_HANDLED; } diff --git a/drivers/sbus/char/cd180.h b/drivers/sbus/char/cd180.h deleted file mode 100644 index 445b86cc65e..00000000000 --- a/drivers/sbus/char/cd180.h +++ /dev/null @@ -1,240 +0,0 @@ - -/* Definitions for Cirrus Logic CL-CD180 8-port async mux chip */ -#define CD180_NCH 8 /* Total number of channels */ -#define CD180_TPC 16 /* Ticks per character */ -#define CD180_NFIFO 8 /* TX FIFO size */ - -/* Global registers */ -#define CD180_GFRCR 0x6b /* Global Firmware Revision Code Register */ -#define CD180_SRCR 0x66 /* Service Request Configuration Register */ -#define CD180_PPRH 0x70 /* Prescaler Period Register High */ -#define CD180_PPRL 0x71 /* Prescaler Period Register Low */ -#define CD180_MSMR 0x61 /* Modem Service Match Register */ -#define CD180_TSMR 0x62 /* Transmit Service Match Register */ -#define CD180_RSMR 0x63 /* Receive Service Match Register */ -#define CD180_GSVR 0x40 /* Global Service Vector Register */ -#define CD180_SRSR 0x65 /* Service Request Status Register */ -#define CD180_GSCR 0x41 /* Global Service Channel Register */ -#define CD180_CAR 0x64 /* Channel Access Register */ - -/* Indexed registers */ -#define CD180_RDCR 0x07 /* Receive Data Count Register */ -#define CD180_RDR 0x78 /* Receiver Data Register */ -#define CD180_RCSR 0x7a /* Receiver Character Status Register */ -#define CD180_TDR 0x7b /* Transmit Data Register */ -#define CD180_EOSRR 0x7f /* End of Service Request Register */ - -/* Channel Registers */ -#define CD180_SRER 0x02 /* Service Request Enable Register */ -#define CD180_CCR 0x01 /* Channel Command Register */ -#define CD180_COR1 0x03 /* Channel Option Register 1 */ -#define CD180_COR2 0x04 /* Channel Option Register 2 */ -#define CD180_COR3 0x05 /* Channel Option Register 3 */ -#define CD180_CCSR 0x06 /* Channel Control Status Register */ -#define CD180_RTPR 0x18 /* Receive Timeout Period Register */ -#define CD180_RBPRH 0x31 /* Receive Bit Rate Period Register High */ -#define CD180_RBPRL 0x32 /* Receive Bit Rate Period Register Low */ -#define CD180_TBPRH 0x39 /* Transmit Bit Rate Period Register High */ -#define CD180_TBPRL 0x3a /* Transmit Bit Rate Period Register Low */ -#define CD180_SCHR1 0x09 /* Special Character Register 1 */ -#define CD180_SCHR2 0x0a /* Special Character Register 2 */ -#define CD180_SCHR3 0x0b /* Special Character Register 3 */ -#define CD180_SCHR4 0x0c /* Special Character Register 4 */ -#define CD180_MCR 0x12 /* Modem Change Register */ -#define CD180_MCOR1 0x10 /* Modem Change Option 1 Register */ -#define CD180_MCOR2 0x11 /* Modem Change Option 2 Register */ -#define CD180_MSVR 0x28 /* Modem Signal Value Register */ -#define CD180_MSVRTS 0x29 /* Modem Signal Value RTS */ -#define CD180_MSVDTR 0x2a /* Modem Signal Value DTR */ - -/* Global Interrupt Vector Register (R/W) */ - -#define GSVR_ITMASK 0x07 /* Interrupt type mask */ -#define GSVR_IT_MDM 0x01 /* Modem Signal Change Interrupt */ -#define GSVR_IT_TX 0x02 /* Transmit Data Interrupt */ -#define GSVR_IT_RGD 0x03 /* Receive Good Data Interrupt */ -#define GSVR_IT_REXC 0x07 /* Receive Exception Interrupt */ - - -/* Global Interrupt Channel Register (R/W) */ - -#define GSCR_CHAN 0x1c /* Channel Number Mask */ -#define GSCR_CHAN_OFF 2 /* Channel Number Offset */ - - -/* Channel Address Register (R/W) */ - -#define CAR_CHAN 0x07 /* Channel Number Mask */ - - -/* Receive Character Status Register (R/O) */ - -#define RCSR_TOUT 0x80 /* Rx Timeout */ -#define RCSR_SCDET 0x70 /* Special Character Detected Mask */ -#define RCSR_NO_SC 0x00 /* No Special Characters Detected */ -#define RCSR_SC_1 0x10 /* Special Char 1 (or 1 & 3) Detected */ -#define RCSR_SC_2 0x20 /* Special Char 2 (or 2 & 4) Detected */ -#define RCSR_SC_3 0x30 /* Special Char 3 Detected */ -#define RCSR_SC_4 0x40 /* Special Char 4 Detected */ -#define RCSR_BREAK 0x08 /* Break has been detected */ -#define RCSR_PE 0x04 /* Parity Error */ -#define RCSR_FE 0x02 /* Frame Error */ -#define RCSR_OE 0x01 /* Overrun Error */ - - -/* Channel Command Register (R/W) (commands in groups can be OR-ed) */ - -#define CCR_HARDRESET 0x81 /* Reset the chip */ - -#define CCR_SOFTRESET 0x80 /* Soft Channel Reset */ - -#define CCR_CORCHG1 0x42 /* Channel Option Register 1 Changed */ -#define CCR_CORCHG2 0x44 /* Channel Option Register 2 Changed */ -#define CCR_CORCHG3 0x48 /* Channel Option Register 3 Changed */ - -#define CCR_SSCH1 0x21 /* Send Special Character 1 */ - -#define CCR_SSCH2 0x22 /* Send Special Character 2 */ - -#define CCR_SSCH3 0x23 /* Send Special Character 3 */ - -#define CCR_SSCH4 0x24 /* Send Special Character 4 */ - -#define CCR_TXEN 0x18 /* Enable Transmitter */ -#define CCR_RXEN 0x12 /* Enable Receiver */ - -#define CCR_TXDIS 0x14 /* Disable Transmitter */ -#define CCR_RXDIS 0x11 /* Disable Receiver */ - - -/* Service Request Enable Register (R/W) */ - -#define SRER_DSR 0x80 /* Enable interrupt on DSR change */ -#define SRER_CD 0x40 /* Enable interrupt on CD change */ -#define SRER_CTS 0x20 /* Enable interrupt on CTS change */ -#define SRER_RXD 0x10 /* Enable interrupt on Receive Data */ -#define SRER_RXSC 0x08 /* Enable interrupt on Receive Spec. Char */ -#define SRER_TXRDY 0x04 /* Enable interrupt on TX FIFO empty */ -#define SRER_TXEMPTY 0x02 /* Enable interrupt on TX completely empty */ -#define SRER_RET 0x01 /* Enable interrupt on RX Exc. Timeout */ - - -/* Channel Option Register 1 (R/W) */ - -#define COR1_ODDP 0x80 /* Odd Parity */ -#define COR1_PARMODE 0x60 /* Parity Mode mask */ -#define COR1_NOPAR 0x00 /* No Parity */ -#define COR1_FORCEPAR 0x20 /* Force Parity */ -#define COR1_NORMPAR 0x40 /* Normal Parity */ -#define COR1_IGNORE 0x10 /* Ignore Parity on RX */ -#define COR1_STOPBITS 0x0c /* Number of Stop Bits */ -#define COR1_1SB 0x00 /* 1 Stop Bit */ -#define COR1_15SB 0x04 /* 1.5 Stop Bits */ -#define COR1_2SB 0x08 /* 2 Stop Bits */ -#define COR1_CHARLEN 0x03 /* Character Length */ -#define COR1_5BITS 0x00 /* 5 bits */ -#define COR1_6BITS 0x01 /* 6 bits */ -#define COR1_7BITS 0x02 /* 7 bits */ -#define COR1_8BITS 0x03 /* 8 bits */ - - -/* Channel Option Register 2 (R/W) */ - -#define COR2_IXM 0x80 /* Implied XON mode */ -#define COR2_TXIBE 0x40 /* Enable In-Band (XON/XOFF) Flow Control */ -#define COR2_ETC 0x20 /* Embedded Tx Commands Enable */ -#define COR2_LLM 0x10 /* Local Loopback Mode */ -#define COR2_RLM 0x08 /* Remote Loopback Mode */ -#define COR2_RTSAO 0x04 /* RTS Automatic Output Enable */ -#define COR2_CTSAE 0x02 /* CTS Automatic Enable */ -#define COR2_DSRAE 0x01 /* DSR Automatic Enable */ - - -/* Channel Option Register 3 (R/W) */ - -#define COR3_XONCH 0x80 /* XON is a pair of characters (1 & 3) */ -#define COR3_XOFFCH 0x40 /* XOFF is a pair of characters (2 & 4) */ -#define COR3_FCT 0x20 /* Flow-Control Transparency Mode */ -#define COR3_SCDE 0x10 /* Special Character Detection Enable */ -#define COR3_RXTH 0x0f /* RX FIFO Threshold value (1-8) */ - - -/* Channel Control Status Register (R/O) */ - -#define CCSR_RXEN 0x80 /* Receiver Enabled */ -#define CCSR_RXFLOFF 0x40 /* Receive Flow Off (XOFF was sent) */ -#define CCSR_RXFLON 0x20 /* Receive Flow On (XON was sent) */ -#define CCSR_TXEN 0x08 /* Transmitter Enabled */ -#define CCSR_TXFLOFF 0x04 /* Transmit Flow Off (got XOFF) */ -#define CCSR_TXFLON 0x02 /* Transmit Flow On (got XON) */ - - -/* Modem Change Option Register 1 (R/W) */ - -#define MCOR1_DSRZD 0x80 /* Detect 0->1 transition of DSR */ -#define MCOR1_CDZD 0x40 /* Detect 0->1 transition of CD */ -#define MCOR1_CTSZD 0x20 /* Detect 0->1 transition of CTS */ -#define MCOR1_DTRTH 0x0f /* Auto DTR flow control Threshold (1-8) */ -#define MCOR1_NODTRFC 0x0 /* Automatic DTR flow control disabled */ - - -/* Modem Change Option Register 2 (R/W) */ - -#define MCOR2_DSROD 0x80 /* Detect 1->0 transition of DSR */ -#define MCOR2_CDOD 0x40 /* Detect 1->0 transition of CD */ -#define MCOR2_CTSOD 0x20 /* Detect 1->0 transition of CTS */ - - -/* Modem Change Register (R/W) */ - -#define MCR_DSRCHG 0x80 /* DSR Changed */ -#define MCR_CDCHG 0x40 /* CD Changed */ -#define MCR_CTSCHG 0x20 /* CTS Changed */ - - -/* Modem Signal Value Register (R/W) */ - -#define MSVR_DSR 0x80 /* Current state of DSR input */ -#define MSVR_CD 0x40 /* Current state of CD input */ -#define MSVR_CTS 0x20 /* Current state of CTS input */ -#define MSVR_DTR 0x02 /* Current state of DTR output */ -#define MSVR_RTS 0x01 /* Current state of RTS output */ - - -/* Service Request Status Register */ - -#define SRSR_CMASK 0xC0 /* Current Service Context Mask */ -#define SRSR_CNONE 0x00 /* Not in a service context */ -#define SRSR_CRX 0x40 /* Rx Context */ -#define SRSR_CTX 0x80 /* Tx Context */ -#define SRSR_CMDM 0xC0 /* Modem Context */ -#define SRSR_ANYINT 0x6F /* Any interrupt flag */ -#define SRSR_RINT 0x10 /* Receive Interrupt */ -#define SRSR_TINT 0x04 /* Transmit Interrupt */ -#define SRSR_MINT 0x01 /* Modem Interrupt */ -#define SRSR_REXT 0x20 /* Receive External Interrupt */ -#define SRSR_TEXT 0x08 /* Transmit External Interrupt */ -#define SRSR_MEXT 0x02 /* Modem External Interrupt */ - - -/* Service Request Configuration Register */ - -#define SRCR_PKGTYPE 0x80 -#define SRCR_REGACKEN 0x40 -#define SRCR_DAISYEN 0x20 -#define SRCR_GLOBPRI 0x10 -#define SRCR_UNFAIR 0x08 -#define SRCR_AUTOPRI 0x02 -#define SRCR_PRISEL 0x01 - -/* Values for register-based Interrupt ACKs */ -#define CD180_ACK_MINT 0x75 /* goes to MSMR */ -#define CD180_ACK_TINT 0x76 /* goes to TSMR */ -#define CD180_ACK_RINT 0x77 /* goes to RSMR */ - -/* Escape characters */ - -#define CD180_C_ESC 0x00 /* Escape character */ -#define CD180_C_SBRK 0x81 /* Start sending BREAK */ -#define CD180_C_DELAY 0x82 /* Delay output */ -#define CD180_C_EBRK 0x83 /* Stop sending BREAK */ diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 45cf5bc0bbe..44d2ef906ac 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -364,6 +364,7 @@ static int __init ts102_uctrl_init(void) struct linux_prom_irqs tmp_irq[2]; unsigned int vaddr[2] = { 0, 0 }; int tmpnode, uctrlnode = prom_getchild(prom_root_node); + int err; tmpnode = prom_searchsiblings(uctrlnode, "obio"); @@ -389,7 +390,12 @@ static int __init ts102_uctrl_init(void) if(!driver->irq) driver->irq = tmp_irq[0].pri; - request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); + err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); + if (err) { + printk("%s: unable to register irq %d\n", + __FUNCTION__, driver->irq); + return err; + } if (misc_register(&uctrl_dev)) { printk("%s: unable to get misc minor %d\n", diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c index d2d51dc51ab..82add77ad13 100644 --- a/drivers/scsi/arm/cumana_2.c +++ b/drivers/scsi/arm/cumana_2.c @@ -178,10 +178,10 @@ cumanascsi_2_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp, dma_dir = DMA_MODE_READ, alatch_dir = ALATCH_DMA_IN; - dma_map_sg(dev, info->sg, bufs + 1, map_dir); + dma_map_sg(dev, info->sg, bufs, map_dir); disable_dma(dmach); - set_dma_sg(dmach, info->sg, bufs + 1); + set_dma_sg(dmach, info->sg, bufs); writeb(alatch_dir, info->base + CUMANASCSI2_ALATCH); set_dma_mode(dmach, dma_dir); enable_dma(dmach); diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c index d4136524fc4..ed06a8c19ad 100644 --- a/drivers/scsi/arm/eesox.c +++ b/drivers/scsi/arm/eesox.c @@ -175,10 +175,10 @@ eesoxscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp, map_dir = DMA_FROM_DEVICE, dma_dir = DMA_MODE_READ; - dma_map_sg(dev, info->sg, bufs + 1, map_dir); + dma_map_sg(dev, info->sg, bufs, map_dir); disable_dma(dmach); - set_dma_sg(dmach, info->sg, bufs + 1); + set_dma_sg(dmach, info->sg, bufs); set_dma_mode(dmach, dma_dir); enable_dma(dmach); return fasdma_real_all; diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index 2969cc0ff25..fb5f2028438 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -633,7 +633,7 @@ static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) BUG_ON(bytes_transferred < 0); - info->SCpnt->request_bufflen -= bytes_transferred; + SCp->phase -= bytes_transferred; while (bytes_transferred != 0) { if (SCp->this_residual > bytes_transferred) @@ -715,7 +715,7 @@ static void fas216_cleanuptransfer(FAS216_Info *info) return; if (dmatype == fasdma_real_all) - total = info->SCpnt->request_bufflen; + total = info->scsi.SCp.phase; else total = info->scsi.SCp.this_residual; @@ -753,7 +753,7 @@ static void fas216_transfer(FAS216_Info *info) fas216_log(info, LOG_BUFFER, "starttransfer: buffer %p length 0x%06x reqlen 0x%06x", info->scsi.SCp.ptr, info->scsi.SCp.this_residual, - info->SCpnt->request_bufflen); + info->scsi.SCp.phase); if (!info->scsi.SCp.ptr) { fas216_log(info, LOG_ERROR, "null buffer passed to " @@ -784,7 +784,7 @@ static void fas216_transfer(FAS216_Info *info) info->dma.transfer_type = dmatype; if (dmatype == fasdma_real_all) - fas216_set_stc(info, info->SCpnt->request_bufflen); + fas216_set_stc(info, info->scsi.SCp.phase); else fas216_set_stc(info, info->scsi.SCp.this_residual); @@ -2114,6 +2114,7 @@ request_sense: SCpnt->SCp.buffers_residual = 0; SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer; SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer); + SCpnt->SCp.phase = sizeof(SCpnt->sense_buffer); SCpnt->SCp.Message = 0; SCpnt->SCp.Status = 0; SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c index f9cd20bfb95..159047a3499 100644 --- a/drivers/scsi/arm/powertec.c +++ b/drivers/scsi/arm/powertec.c @@ -148,10 +148,10 @@ powertecscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp, map_dir = DMA_FROM_DEVICE, dma_dir = DMA_MODE_READ; - dma_map_sg(dev, info->sg, bufs + 1, map_dir); + dma_map_sg(dev, info->sg, bufs, map_dir); disable_dma(dmach); - set_dma_sg(dmach, info->sg, bufs + 1); + set_dma_sg(dmach, info->sg, bufs); set_dma_mode(dmach, dma_dir); enable_dma(dmach); return fasdma_real_all; @@ -342,6 +342,7 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id) info->base = base; powertecscsi_terminator_ctl(host, term[ec->slot_no]); + info->ec = ec; info->info.scsi.io_base = base + POWERTEC_FAS216_OFFSET; info->info.scsi.io_shift = POWERTEC_FAS216_SHIFT; info->info.scsi.irq = ec->irq; diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h index 3a39579bd08..21ba57155be 100644 --- a/drivers/scsi/arm/scsi.h +++ b/drivers/scsi/arm/scsi.h @@ -80,6 +80,7 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt) (page_address(SCpnt->SCp.buffer->page) + SCpnt->SCp.buffer->offset); SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.phase = SCpnt->request_bufflen; #ifdef BELT_AND_BRACES /* @@ -98,6 +99,7 @@ static inline void init_SCp(struct scsi_cmnd *SCpnt) } else { SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer; SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.phase = SCpnt->request_bufflen; } /* diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index 587d87b9eb3..d31721f2744 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -170,8 +170,7 @@ static void dz_enable_ms(struct uart_port *port) * This routine deals with inputs from any lines. * ------------------------------------------------------------ */ -static inline void dz_receive_chars(struct dz_port *dport_in, - struct pt_regs *regs) +static inline void dz_receive_chars(struct dz_port *dport_in) { struct dz_port *dport; struct tty_struct *tty = NULL; @@ -226,7 +225,7 @@ static inline void dz_receive_chars(struct dz_port *dport_in, break; } - if (uart_handle_sysrq_char(&dport->port, ch, regs)) + if (uart_handle_sysrq_char(&dport->port, ch)) continue; if ((status & dport->port.ignore_status_mask) == 0) { @@ -332,7 +331,7 @@ static irqreturn_t dz_interrupt(int irq, void *dev) status = dz_in(dport, DZ_CSR); if ((status & (DZ_RDONE | DZ_RIE)) == (DZ_RDONE | DZ_RIE)) - dz_receive_chars(dport, regs); + dz_receive_chars(dport); if ((status & (DZ_TRDY | DZ_TIE)) == (DZ_TRDY | DZ_TIE)) dz_transmit_chars(dport); diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 08430961a89..99af084c7ce 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -425,15 +425,13 @@ irqreturn_t mcfrs_interrupt(int irq, void *dev_id) * ------------------------------------------------------------------- */ -static void mcfrs_offintr(void *private) +static void mcfrs_offintr(struct work_struct *work) { - struct mcf_serial *info = (struct mcf_serial *) private; - struct tty_struct *tty; + struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue); + struct tty_struct *tty = info->tty; - tty = info->tty; - if (!tty) - return; - tty_wakeup(tty); + if (tty) + tty_wakeup(tty); } @@ -497,16 +495,13 @@ static void mcfrs_timer(void) * do_serial_hangup() -> tty->hangup() -> mcfrs_hangup() * */ -static void do_serial_hangup(void *private) +static void do_serial_hangup(struct work_struct *work) { - struct mcf_serial *info = (struct mcf_serial *) private; - struct tty_struct *tty; + struct mcf_serial *info = container_of(work, struct mcf_serial, tqueue_hangup); + struct tty_struct *tty = info->tty; - tty = info->tty; - if (!tty) - return; - - tty_hangup(tty); + if (tty) + tty_hangup(tty); } static int startup(struct mcf_serial * info) @@ -857,7 +852,7 @@ static void mcfrs_throttle(struct tty_struct * tty) #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("throttle %s: %d....\n", _tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif @@ -876,7 +871,7 @@ static void mcfrs_unthrottle(struct tty_struct * tty) #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + printk("unthrottle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif @@ -1541,8 +1536,8 @@ static void mcfrs_irqinit(struct mcf_serial *info) * External Pin Mask Setting & Enable External Pin for Interface * mrcbis@aliceposta.it */ - unsigned short *serpin_enable_mask; - serpin_enable_mask = (MCF_IPSBAR + MCF_GPIO_PAR_UART); + u16 *serpin_enable_mask; + serpin_enable_mask = (u16 *) (MCF_IPSBAR + MCF_GPIO_PAR_UART); if (info->line == 0) *serpin_enable_mask |= UART0_ENABLE_MASK; else if (info->line == 1) @@ -1551,6 +1546,13 @@ static void mcfrs_irqinit(struct mcf_serial *info) *serpin_enable_mask |= UART2_ENABLE_MASK; } #endif +#if defined(CONFIG_M528x) + /* make sure PUAPAR is set for UART0 and UART1 */ + if (info->line < 2) { + volatile unsigned char *portp = (volatile unsigned char *) (MCF_MBAR + MCF5282_GPIO_PUAPAR); + *portp |= (0x03 << (info->line * 2)); + } +#endif #elif defined(CONFIG_M520x) volatile unsigned char *icrp, *uartp; volatile unsigned long *imrp; @@ -1783,8 +1785,8 @@ mcfrs_init(void) info->event = 0; info->count = 0; info->blocked_open = 0; - INIT_WORK(&info->tqueue, mcfrs_offintr, info); - INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); + INIT_WORK(&info->tqueue, mcfrs_offintr); + INIT_WORK(&info->tqueue_hangup, do_serial_hangup); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c index ccb8fa1800a..83211013deb 100644 --- a/drivers/serial/mux.c +++ b/drivers/serial/mux.c @@ -51,7 +51,11 @@ #define MUX_NR 256 static unsigned int port_cnt __read_mostly; -static struct uart_port mux_ports[MUX_NR]; +struct mux_port { + struct uart_port port; + int enabled; +}; +static struct mux_port mux_ports[MUX_NR]; static struct uart_driver mux_driver = { .owner = THIS_MODULE, @@ -66,7 +70,36 @@ static struct timer_list mux_timer; #define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET) #define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET) -#define GET_MUX_PORTS(iodc_data) ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8 + +/** + * get_mux_port_count - Get the number of available ports on the Mux. + * @dev: The parisc device. + * + * This function is used to determine the number of ports the Mux + * supports. The IODC data reports the number of ports the Mux + * can support, but there are cases where not all the Mux ports + * are connected. This function can override the IODC and + * return the true port count. + */ +static int __init get_mux_port_count(struct parisc_device *dev) +{ + int status; + u8 iodc_data[32]; + unsigned long bytecnt; + + /* If this is the built-in Mux for the K-Class (Eole CAP/MUX), + * we only need to allocate resources for 1 port since the + * other 7 ports are not connected. + */ + if(dev->id.hversion == 0x15) + return 1; + + status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32); + BUG_ON(status != PDC_OK); + + /* Return the number of ports specified in the iodc data. */ + return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8; +} /** * mux_tx_empty - Check if the transmitter fifo is empty. @@ -250,7 +283,7 @@ static void mux_read(struct uart_port *port) */ static int mux_startup(struct uart_port *port) { - mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); + mux_ports[port->line].enabled = 1; return 0; } @@ -262,6 +295,7 @@ static int mux_startup(struct uart_port *port) */ static void mux_shutdown(struct uart_port *port) { + mux_ports[port->line].enabled = 0; } /** @@ -319,7 +353,7 @@ static int mux_request_port(struct uart_port *port) * @port: Ptr to the uart_port. * @type: Bitmask of required configurations. * - * Perform any autoconfiguration steps for the port. This functino is + * Perform any autoconfiguration steps for the port. This function is * called if the UPF_BOOT_AUTOCONF flag is specified for the port. * [Note: This is required for now because of a bug in the Serial core. * rmk has already submitted a patch to linus, should be available for @@ -357,11 +391,11 @@ static void mux_poll(unsigned long unused) int i; for(i = 0; i < port_cnt; ++i) { - if(!mux_ports[i].info) + if(!mux_ports[i].enabled) continue; - mux_read(&mux_ports[i]); - mux_write(&mux_ports[i]); + mux_read(&mux_ports[i].port); + mux_write(&mux_ports[i].port); } mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); @@ -371,8 +405,17 @@ static void mux_poll(unsigned long unused) #ifdef CONFIG_SERIAL_MUX_CONSOLE static void mux_console_write(struct console *co, const char *s, unsigned count) { - while(count--) - pdc_iodc_putc(*s++); + /* Wait until the FIFO drains. */ + while(UART_GET_FIFO_CNT(&mux_ports[0].port)) + udelay(1); + + while(count--) { + if(*s == '\n') { + UART_PUT_CHAR(&mux_ports[0].port, '\r'); + } + UART_PUT_CHAR(&mux_ports[0].port, *s++); + } + } static int mux_console_setup(struct console *co, char *options) @@ -428,19 +471,14 @@ static struct uart_ops mux_pops = { */ static int __init mux_probe(struct parisc_device *dev) { - int i, status, ports; - u8 iodc_data[32]; - unsigned long bytecnt; - struct uart_port *port; + int i, status; - status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32); - if(status != PDC_OK) { - printk(KERN_ERR "Serial mux: Unable to read IODC.\n"); - return 1; - } + int port_count = get_mux_port_count(dev); + printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count); - ports = GET_MUX_PORTS(iodc_data); - printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.3\n", ports); + dev_set_drvdata(&dev->dev, (void *)(long)port_count); + request_mem_region(dev->hpa.start + MUX_OFFSET, + port_count * MUX_LINE_OFFSET, "Mux"); if(!port_cnt) { mux_driver.cons = MUX_CONSOLE; @@ -450,13 +488,10 @@ static int __init mux_probe(struct parisc_device *dev) printk(KERN_ERR "Serial mux: Unable to register driver.\n"); return 1; } - - init_timer(&mux_timer); - mux_timer.function = mux_poll; } - for(i = 0; i < ports; ++i, ++port_cnt) { - port = &mux_ports[port_cnt]; + for(i = 0; i < port_count; ++i, ++port_cnt) { + struct uart_port *port = &mux_ports[port_cnt].port; port->iobase = 0; port->mapbase = dev->hpa.start + MUX_OFFSET + (i * MUX_LINE_OFFSET); @@ -477,27 +512,73 @@ static int __init mux_probe(struct parisc_device *dev) */ port->timeout = HZ / 50; spin_lock_init(&port->lock); + status = uart_add_one_port(&mux_driver, port); BUG_ON(status); } -#ifdef CONFIG_SERIAL_MUX_CONSOLE - register_console(&mux_console); -#endif return 0; } +static int __devexit mux_remove(struct parisc_device *dev) +{ + int i, j; + int port_count = (long)dev_get_drvdata(&dev->dev); + + /* Find Port 0 for this card in the mux_ports list. */ + for(i = 0; i < port_cnt; ++i) { + if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET) + break; + } + BUG_ON(i + port_count > port_cnt); + + /* Release the resources associated with each port on the device. */ + for(j = 0; j < port_count; ++j, ++i) { + struct uart_port *port = &mux_ports[i].port; + + uart_remove_one_port(&mux_driver, port); + if(port->membase) + iounmap(port->membase); + } + + release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET); + return 0; +} + +/* Hack. This idea was taken from the 8250_gsc.c on how to properly order + * the serial port detection in the proper order. The idea is we always + * want the builtin mux to be detected before addin mux cards, so we + * specifically probe for the builtin mux cards first. + * + * This table only contains the parisc_device_id of known builtin mux + * devices. All other mux cards will be detected by the generic mux_tbl. + */ +static struct parisc_device_id builtin_mux_tbl[] = { + { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */ + { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */ + { 0, } +}; + static struct parisc_device_id mux_tbl[] = { { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D }, { 0, } }; +MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl); MODULE_DEVICE_TABLE(parisc, mux_tbl); +static struct parisc_driver builtin_serial_mux_driver = { + .name = "builtin_serial_mux", + .id_table = builtin_mux_tbl, + .probe = mux_probe, + .remove = __devexit_p(mux_remove), +}; + static struct parisc_driver serial_mux_driver = { .name = "serial_mux", .id_table = mux_tbl, .probe = mux_probe, + .remove = __devexit_p(mux_remove), }; /** @@ -507,7 +588,21 @@ static struct parisc_driver serial_mux_driver = { */ static int __init mux_init(void) { - return register_parisc_driver(&serial_mux_driver); + register_parisc_driver(&builtin_serial_mux_driver); + register_parisc_driver(&serial_mux_driver); + + if(port_cnt > 0) { + /* Start the Mux timer */ + init_timer(&mux_timer); + mux_timer.function = mux_poll; + mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); + +#ifdef CONFIG_SERIAL_MUX_CONSOLE + register_console(&mux_console); +#endif + } + + return 0; } /** @@ -517,14 +612,16 @@ static int __init mux_init(void) */ static void __exit mux_exit(void) { - int i; - - for (i = 0; i < port_cnt; i++) { - uart_remove_one_port(&mux_driver, &mux_ports[i]); - if (mux_ports[i].membase) - iounmap(mux_ports[i].membase); + /* Delete the Mux timer. */ + if(port_cnt > 0) { + del_timer(&mux_timer); +#ifdef CONFIG_SERIAL_MUX_CONSOLE + unregister_console(&mux_console); +#endif } + unregister_parisc_driver(&builtin_serial_mux_driver); + unregister_parisc_driver(&serial_mux_driver); uart_unregister_driver(&mux_driver); } diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c index f4440d32931..509ace7e688 100644 --- a/drivers/serial/serial_txx9.c +++ b/drivers/serial/serial_txx9.c @@ -38,6 +38,8 @@ * Fix some spin_locks. * Do not call uart_add_one_port for absent ports. * 1.07 Use CONFIG_SERIAL_TXX9_NR_UARTS. Cleanup. + * 1.08 Use platform_device. + * Fix and cleanup suspend/resume/initialization codes. */ #if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -50,7 +52,7 @@ #include <linux/console.h> #include <linux/sysrq.h> #include <linux/delay.h> -#include <linux/device.h> +#include <linux/platform_device.h> #include <linux/pci.h> #include <linux/tty.h> #include <linux/tty_flip.h> @@ -60,7 +62,7 @@ #include <asm/io.h> -static char *serial_version = "1.07"; +static char *serial_version = "1.08"; static char *serial_name = "TX39/49 Serial driver"; #define PASS_LIMIT 256 @@ -94,12 +96,7 @@ static char *serial_name = "TX39/49 Serial driver"; struct uart_txx9_port { struct uart_port port; - - /* - * We provide a per-port pm hook. - */ - void (*pm)(struct uart_port *port, - unsigned int state, unsigned int old); + /* No additional info for now */ }; #define TXX9_REGION_SIZE 0x24 @@ -277,6 +274,31 @@ static void serial_txx9_enable_ms(struct uart_port *port) /* TXX9-SIO can not control DTR... */ } +static void serial_txx9_initialize(struct uart_port *port) +{ + struct uart_txx9_port *up = (struct uart_txx9_port *)port; + unsigned int tmout = 10000; + + sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST); + /* TX4925 BUG WORKAROUND. Accessing SIOC register + * immediately after soft reset causes bus error. */ + mmiowb(); + udelay(1); + while ((sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) && --tmout) + udelay(1); + /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ + sio_set(up, TXX9_SIFCR, + TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1); + /* initial settings */ + sio_out(up, TXX9_SILCR, + TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT | + ((up->port.flags & UPF_TXX9_USE_SCLK) ? + TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG)); + sio_quot_set(up, uart_get_divisor(port, 9600)); + sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */); + sio_out(up, TXX9_SIDICR, 0); +} + static inline void receive_chars(struct uart_txx9_port *up, unsigned int *status) { @@ -657,9 +679,8 @@ static void serial_txx9_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uart_txx9_port *up = (struct uart_txx9_port *)port; - if (up->pm) - up->pm(port, state, oldstate); + if (state == 0) + serial_txx9_initialize(port); } static int serial_txx9_request_resource(struct uart_txx9_port *up) @@ -732,7 +753,6 @@ static int serial_txx9_request_port(struct uart_port *port) static void serial_txx9_config_port(struct uart_port *port, int uflags) { struct uart_txx9_port *up = (struct uart_txx9_port *)port; - unsigned long flags; int ret; /* @@ -749,30 +769,7 @@ static void serial_txx9_config_port(struct uart_port *port, int uflags) if (up->port.line == up->port.cons->index) return; #endif - spin_lock_irqsave(&up->port.lock, flags); - /* - * Reset the UART. - */ - sio_out(up, TXX9_SIFCR, TXX9_SIFCR_SWRST); -#ifdef CONFIG_CPU_TX49XX - /* TX4925 BUG WORKAROUND. Accessing SIOC register - * immediately after soft reset causes bus error. */ - iob(); - udelay(1); -#endif - while (sio_in(up, TXX9_SIFCR) & TXX9_SIFCR_SWRST) - ; - /* TX Int by FIFO Empty, RX Int by Receiving 1 char. */ - sio_set(up, TXX9_SIFCR, - TXX9_SIFCR_TDIL_MAX | TXX9_SIFCR_RDIL_1); - /* initial settings */ - sio_out(up, TXX9_SILCR, - TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT | - ((up->port.flags & UPF_TXX9_USE_SCLK) ? - TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG)); - sio_quot_set(up, uart_get_divisor(port, 9600)); - sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */); - spin_unlock_irqrestore(&up->port.lock, flags); + serial_txx9_initialize(port); } static int @@ -818,7 +815,8 @@ static struct uart_ops serial_txx9_pops = { static struct uart_txx9_port serial_txx9_ports[UART_NR]; -static void __init serial_txx9_register_ports(struct uart_driver *drv) +static void __init serial_txx9_register_ports(struct uart_driver *drv, + struct device *dev) { int i; @@ -827,6 +825,7 @@ static void __init serial_txx9_register_ports(struct uart_driver *drv) up->port.line = i; up->port.ops = &serial_txx9_pops; + up->port.dev = dev; if (up->port.iobase || up->port.mapbase) uart_add_one_port(drv, &up->port); } @@ -898,7 +897,7 @@ serial_txx9_console_write(struct console *co, const char *s, unsigned int count) sio_out(up, TXX9_SIDICR, ier); } -static int serial_txx9_console_setup(struct console *co, char *options) +static int __init serial_txx9_console_setup(struct console *co, char *options) { struct uart_port *port; struct uart_txx9_port *up; @@ -919,17 +918,7 @@ static int serial_txx9_console_setup(struct console *co, char *options) if (!port->ops) return -ENODEV; - /* - * Disable UART interrupts, set DTR and RTS high - * and set speed. - */ - sio_out(up, TXX9_SIDICR, 0); - /* initial settings */ - sio_out(up, TXX9_SILCR, - TXX9_SILCR_UMODE_8BIT | TXX9_SILCR_USBL_1BIT | - ((port->flags & UPF_TXX9_USE_SCLK) ? - TXX9_SILCR_SCS_SCLK_BG : TXX9_SILCR_SCS_IMCLK_BG)); - sio_out(up, TXX9_SIFLCR, TXX9_SIFLCR_RTSTL_MAX /* 15 */); + serial_txx9_initialize(&up->port); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -981,31 +970,6 @@ int __init early_serial_txx9_setup(struct uart_port *port) return 0; } -#ifdef ENABLE_SERIAL_TXX9_PCI -#ifdef CONFIG_PM -/** - * serial_txx9_suspend_port - suspend one serial port - * @line: serial line number - * - * Suspend one serial port. - */ -static void serial_txx9_suspend_port(int line) -{ - uart_suspend_port(&serial_txx9_reg, &serial_txx9_ports[line].port); -} - -/** - * serial_txx9_resume_port - resume one serial port - * @line: serial line number - * - * Resume one serial port. - */ -static void serial_txx9_resume_port(int line) -{ - uart_resume_port(&serial_txx9_reg, &serial_txx9_ports[line].port); -} -#endif - static DEFINE_MUTEX(serial_txx9_mutex); /** @@ -1028,8 +992,18 @@ static int __devinit serial_txx9_register_port(struct uart_port *port) mutex_lock(&serial_txx9_mutex); for (i = 0; i < UART_NR; i++) { uart = &serial_txx9_ports[i]; - if (!(uart->port.iobase || uart->port.mapbase)) + if (uart_match_port(&uart->port, port)) { + uart_remove_one_port(&serial_txx9_reg, &uart->port); break; + } + } + if (i == UART_NR) { + /* Find unused port */ + for (i = 0; i < UART_NR; i++) { + uart = &serial_txx9_ports[i]; + if (!(uart->port.iobase || uart->port.mapbase)) + break; + } } if (i < UART_NR) { uart->port.iobase = port->iobase; @@ -1072,6 +1046,95 @@ static void __devexit serial_txx9_unregister_port(int line) } /* + * Register a set of serial devices attached to a platform device. + */ +static int __devinit serial_txx9_probe(struct platform_device *dev) +{ + struct uart_port *p = dev->dev.platform_data; + struct uart_port port; + int ret, i; + + memset(&port, 0, sizeof(struct uart_port)); + for (i = 0; p && p->uartclk != 0; p++, i++) { + port.iobase = p->iobase; + port.membase = p->membase; + port.irq = p->irq; + port.uartclk = p->uartclk; + port.iotype = p->iotype; + port.flags = p->flags; + port.mapbase = p->mapbase; + port.dev = &dev->dev; + ret = serial_txx9_register_port(&port); + if (ret < 0) { + dev_err(&dev->dev, "unable to register port at index %d " + "(IO%x MEM%lx IRQ%d): %d\n", i, + p->iobase, p->mapbase, p->irq, ret); + } + } + return 0; +} + +/* + * Remove serial ports registered against a platform device. + */ +static int __devexit serial_txx9_remove(struct platform_device *dev) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_txx9_port *up = &serial_txx9_ports[i]; + + if (up->port.dev == &dev->dev) + serial_txx9_unregister_port(i); + } + return 0; +} + +#ifdef CONFIG_PM +static int serial_txx9_suspend(struct platform_device *dev, pm_message_t state) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_txx9_port *up = &serial_txx9_ports[i]; + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + uart_suspend_port(&serial_txx9_reg, &up->port); + } + + return 0; +} + +static int serial_txx9_resume(struct platform_device *dev) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + struct uart_txx9_port *up = &serial_txx9_ports[i]; + + if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev) + uart_resume_port(&serial_txx9_reg, &up->port); + } + + return 0; +} +#endif + +static struct platform_driver serial_txx9_plat_driver = { + .probe = serial_txx9_probe, + .remove = __devexit_p(serial_txx9_remove), +#ifdef CONFIG_PM + .suspend = serial_txx9_suspend, + .resume = serial_txx9_resume, +#endif + .driver = { + .name = "serial_txx9", + .owner = THIS_MODULE, + }, +}; + +#ifdef ENABLE_SERIAL_TXX9_PCI +/* * Probe one serial board. Unfortunately, there is no rhyme nor reason * to the arrangement of serial ports on a PCI card. */ @@ -1097,20 +1160,22 @@ pciserial_txx9_init_one(struct pci_dev *dev, const struct pci_device_id *ent) line = serial_txx9_register_port(&port); if (line < 0) { printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), line); + pci_disable_device(dev); + return line; } - pci_set_drvdata(dev, (void *)(long)line); + pci_set_drvdata(dev, &serial_txx9_ports[line]); return 0; } static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev) { - int line = (int)(long)pci_get_drvdata(dev); + struct uart_txx9_port *up = pci_get_drvdata(dev); pci_set_drvdata(dev, NULL); - if (line) { - serial_txx9_unregister_port(line); + if (up) { + serial_txx9_unregister_port(up->port.line); pci_disable_device(dev); } } @@ -1118,10 +1183,10 @@ static void __devexit pciserial_txx9_remove_one(struct pci_dev *dev) #ifdef CONFIG_PM static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) { - int line = (int)(long)pci_get_drvdata(dev); + struct uart_txx9_port *up = pci_get_drvdata(dev); - if (line) - serial_txx9_suspend_port(line); + if (up) + uart_suspend_port(&serial_txx9_reg, &up->port); pci_save_state(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; @@ -1129,15 +1194,12 @@ static int pciserial_txx9_suspend_one(struct pci_dev *dev, pm_message_t state) static int pciserial_txx9_resume_one(struct pci_dev *dev) { - int line = (int)(long)pci_get_drvdata(dev); + struct uart_txx9_port *up = pci_get_drvdata(dev); pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); - - if (line) { - pci_enable_device(dev); - serial_txx9_resume_port(line); - } + if (up) + uart_resume_port(&serial_txx9_reg, &up->port); return 0; } #endif @@ -1161,6 +1223,8 @@ static struct pci_driver serial_txx9_pci_driver = { MODULE_DEVICE_TABLE(pci, serial_txx9_pci_tbl); #endif /* ENABLE_SERIAL_TXX9_PCI */ +static struct platform_device *serial_txx9_plat_devs; + static int __init serial_txx9_init(void) { int ret; @@ -1168,13 +1232,39 @@ static int __init serial_txx9_init(void) printk(KERN_INFO "%s version %s\n", serial_name, serial_version); ret = uart_register_driver(&serial_txx9_reg); - if (ret >= 0) { - serial_txx9_register_ports(&serial_txx9_reg); + if (ret) + goto out; + + serial_txx9_plat_devs = platform_device_alloc("serial_txx9", -1); + if (!serial_txx9_plat_devs) { + ret = -ENOMEM; + goto unreg_uart_drv; + } + + ret = platform_device_add(serial_txx9_plat_devs); + if (ret) + goto put_dev; + + serial_txx9_register_ports(&serial_txx9_reg, + &serial_txx9_plat_devs->dev); + + ret = platform_driver_register(&serial_txx9_plat_driver); + if (ret) + goto del_dev; #ifdef ENABLE_SERIAL_TXX9_PCI - ret = pci_register_driver(&serial_txx9_pci_driver); + ret = pci_register_driver(&serial_txx9_pci_driver); #endif - } + if (ret == 0) + goto out; + + del_dev: + platform_device_del(serial_txx9_plat_devs); + put_dev: + platform_device_put(serial_txx9_plat_devs); + unreg_uart_drv: + uart_unregister_driver(&serial_txx9_reg); + out: return ret; } @@ -1185,6 +1275,8 @@ static void __exit serial_txx9_exit(void) #ifdef ENABLE_SERIAL_TXX9_PCI pci_unregister_driver(&serial_txx9_pci_driver); #endif + platform_driver_unregister(&serial_txx9_plat_driver); + platform_device_unregister(serial_txx9_plat_devs); for (i = 0; i < UART_NR; i++) { struct uart_txx9_port *up = &serial_txx9_ports[i]; if (up->port.iobase || up->port.mapbase) diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index 253ceb895ca..a27e9e92cb5 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -636,25 +636,6 @@ static irqreturn_t sn_sal_interrupt(int irq, void *dev_id) } /** - * sn_sal_connect_interrupt - Request interrupt, handled by sn_sal_interrupt - * @port: Our sn_cons_port (which contains the uart port) - * - * returns the console irq if interrupt is successfully registered, else 0 - * - */ -static int sn_sal_connect_interrupt(struct sn_cons_port *port) -{ - if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, - IRQF_DISABLED | IRQF_SHARED, - "SAL console driver", port) >= 0) { - return SGI_UART_VECTOR; - } - - printk(KERN_INFO "sn_console: console proceeding in polled mode\n"); - return 0; -} - -/** * sn_sal_timer_poll - this function handles polled console mode * @data: A pointer to our sn_cons_port (which contains the uart port) * @@ -746,30 +727,31 @@ static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port) * mode. We were previously in asynch/polling mode (using init_timer). * * We attempt to switch to interrupt mode here by calling - * sn_sal_connect_interrupt. If that works out, we enable receive interrupts. + * request_irq. If that works out, we enable receive interrupts. */ static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port) { - int irq; unsigned long flags; - if (!port) - return; - - DPRINTF("sn_console: switching to interrupt driven console\n"); - - spin_lock_irqsave(&port->sc_port.lock, flags); + if (port) { + DPRINTF("sn_console: switching to interrupt driven console\n"); - irq = sn_sal_connect_interrupt(port); + if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, + IRQF_DISABLED | IRQF_SHARED, + "SAL console driver", port) >= 0) { + spin_lock_irqsave(&port->sc_port.lock, flags); + port->sc_port.irq = SGI_UART_VECTOR; + port->sc_ops = &intr_ops; - if (irq) { - port->sc_port.irq = irq; - port->sc_ops = &intr_ops; - - /* turn on receive interrupts */ - ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); + /* turn on receive interrupts */ + ia64_sn_console_intr_enable(SAL_CONSOLE_INTR_RECV); + spin_unlock_irqrestore(&port->sc_port.lock, flags); + } + else { + printk(KERN_INFO + "sn_console: console proceeding in polled mode\n"); + } } - spin_unlock_irqrestore(&port->sc_port.lock, flags); } /* diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 34e9bac319b..b6078706fb9 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -4,7 +4,7 @@ usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \ config.o file.o buffer.o sysfs.o endpoint.o \ - devio.o notify.o generic.o + devio.o notify.o generic.o quirks.o ifeq ($(CONFIG_PCI),y) usbcore-objs += hcd-pci.o diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 2aded261f42..9e3e943f313 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -366,19 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver, EXPORT_SYMBOL(usb_driver_release_interface); /* returns 0 if no match, 1 if match */ -int usb_match_one_id(struct usb_interface *interface, - const struct usb_device_id *id) +int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) { - struct usb_host_interface *intf; - struct usb_device *dev; - - /* proc_connectinfo in devio.c may call us with id == NULL. */ - if (id == NULL) - return 0; - - intf = interface->cur_altsetting; - dev = interface_to_usbdev(interface); - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) return 0; @@ -409,6 +398,26 @@ int usb_match_one_id(struct usb_interface *interface, (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) return 0; + return 1; +} + +/* returns 0 if no match, 1 if match */ +int usb_match_one_id(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_host_interface *intf; + struct usb_device *dev; + + /* proc_connectinfo in devio.c may call us with id == NULL. */ + if (id == NULL) + return 0; + + intf = interface->cur_altsetting; + dev = interface_to_usbdev(interface); + + if (!usb_match_device(dev, id)) + return 0; + /* The interface class, subclass, and protocol should never be * checked for a match if the device class is Vendor Specific, * unless the match record specifies the Vendor ID. */ @@ -954,12 +963,16 @@ static int autosuspend_check(struct usb_device *udev) int i; struct usb_interface *intf; - /* For autosuspend, fail fast if anything is in use. - * Also fail if any interfaces require remote wakeup but it - * isn't available. */ + /* For autosuspend, fail fast if anything is in use or autosuspend + * is disabled. Also fail if any interfaces require remote wakeup + * but it isn't available. + */ udev->do_remote_wakeup = device_may_wakeup(&udev->dev); if (udev->pm_usage_cnt > 0) return -EBUSY; + if (!udev->autosuspend_delay) + return -EPERM; + if (udev->actconfig) { for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; @@ -982,7 +995,7 @@ static int autosuspend_check(struct usb_device *udev) #define autosuspend_check(udev) 0 -#endif +#endif /* CONFIG_USB_SUSPEND */ /** * usb_suspend_both - suspend a USB device and its interfaces @@ -1177,7 +1190,7 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt) udev->pm_usage_cnt -= inc_usage_cnt; } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - USB_AUTOSUSPEND_DELAY); + udev->autosuspend_delay); usb_pm_unlock(udev); return status; } @@ -1212,6 +1225,26 @@ void usb_autosuspend_device(struct usb_device *udev) } /** + * usb_try_autosuspend_device - attempt an autosuspend of a USB device and its interfaces + * @udev: the usb_device to autosuspend + * + * This routine should be called when a core subsystem thinks @udev may + * be ready to autosuspend. + * + * @udev's usage counter left unchanged. If it or any of the usage counters + * for an active interface is greater than 0, or autosuspend is not allowed + * for any other reason, no autosuspend request will be queued. + * + * This routine can run only in process context. + */ +void usb_try_autosuspend_device(struct usb_device *udev) +{ + usb_autopm_do_device(udev, 0); + // dev_dbg(&udev->dev, "%s: cnt %d\n", + // __FUNCTION__, udev->pm_usage_cnt); +} + +/** * usb_autoresume_device - immediately autoresume a USB device and its interfaces * @udev: the usb_device to autoresume * @@ -1261,7 +1294,7 @@ static int usb_autopm_do_interface(struct usb_interface *intf, intf->pm_usage_cnt -= inc_usage_cnt; } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - USB_AUTOSUSPEND_DELAY); + udev->autosuspend_delay); } usb_pm_unlock(udev); return status; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 50c0db15304..41400743ce2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1287,6 +1287,9 @@ int usb_new_device(struct usb_device *udev) if (!try_module_get(THIS_MODULE)) return -EINVAL; + /* Determine quirks */ + usb_detect_quirks(udev); + err = usb_get_configuration(udev); if (err < 0) { dev_err(&udev->dev, "can't read configurations, error %d\n", diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 74edaea5665..2f17468b5c1 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -11,6 +11,7 @@ #include <linux/timer.h> #include <linux/ctype.h> #include <linux/device.h> +#include <linux/usb/quirks.h> #include <asm/byteorder.h> #include <asm/scatterlist.h> @@ -685,7 +686,10 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid, /* Try to read the string descriptor by asking for the maximum * possible number of bytes */ - rc = usb_get_string(dev, langid, index, buf, 255); + if (dev->quirks & USB_QUIRK_STRING_FETCH_255) + rc = -EIO; + else + rc = usb_get_string(dev, langid, index, buf, 255); /* If that failed try to read the descriptor length, then * ask for just that many bytes */ diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c new file mode 100644 index 00000000000..0e5c646cb4f --- /dev/null +++ b/drivers/usb/core/quirks.c @@ -0,0 +1,77 @@ +/* + * USB device quirk handling logic and table + * + * Copyright (c) 2007 Oliver Neukum + * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + * + */ + +#include <linux/usb.h> +#include <linux/usb/quirks.h> +#include "usb.h" + +/* List of quirky USB devices. Please keep this list ordered by: + * 1) Vendor ID + * 2) Product ID + * 3) Class ID + * + * as we want specific devices to be overridden first, and only after that, any + * class specific quirks. + * + * Right now the logic aborts if it finds a valid device in the table, we might + * want to change that in the future if it turns out that a whole class of + * devices is broken... + */ +static const struct usb_device_id usb_quirk_list[] = { + /* HP 5300/5370C scanner */ + { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, + + /* Elsa MicroLink 56k (V.250) */ + { USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND }, + + { } /* terminating entry must be last */ +}; + +static void usb_autosuspend_quirk(struct usb_device *udev) +{ +#ifdef CONFIG_USB_SUSPEND + /* disable autosuspend, but allow the user to re-enable it via sysfs */ + udev->autosuspend_delay = 0; +#endif +} + +static const struct usb_device_id *find_id(struct usb_device *udev) +{ + const struct usb_device_id *id = usb_quirk_list; + + for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass || + id->driver_info; id++) { + if (usb_match_device(udev, id)) + return id; + } + return NULL; +} + +/* + * Detect any quirks the device has, and do any housekeeping for it if needed. + */ +void usb_detect_quirks(struct usb_device *udev) +{ + const struct usb_device_id *id = usb_quirk_list; + + id = find_id(udev); + if (id) + udev->quirks = (u32)(id->driver_info); + if (udev->quirks) + dev_dbg(&udev->dev, "USB quirks for this device: %x\n", + udev->quirks); + + /* do any special quirk handling here if needed */ + if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND) + usb_autosuspend_quirk(udev); +} diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 0edfbafd702..311d5df8038 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -148,6 +148,75 @@ show_maxchild(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL); +static ssize_t +show_quirks(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev; + + udev = to_usb_device(dev); + return sprintf(buf, "0x%x\n", udev->quirks); +} +static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL); + +#ifdef CONFIG_USB_SUSPEND + +static ssize_t +show_autosuspend(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_device *udev = to_usb_device(dev); + + return sprintf(buf, "%u\n", udev->autosuspend_delay / HZ); +} + +static ssize_t +set_autosuspend(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_device *udev = to_usb_device(dev); + unsigned value, old; + + if (sscanf(buf, "%u", &value) != 1 || value >= INT_MAX/HZ) + return -EINVAL; + value *= HZ; + + old = udev->autosuspend_delay; + udev->autosuspend_delay = value; + if (value > 0 && old == 0) + usb_try_autosuspend_device(udev); + + return count; +} + +static DEVICE_ATTR(autosuspend, S_IRUGO | S_IWUSR, + show_autosuspend, set_autosuspend); + +static char power_group[] = "power"; + +static int add_power_attributes(struct device *dev) +{ + int rc = 0; + + if (is_usb_device(dev)) + rc = sysfs_add_file_to_group(&dev->kobj, + &dev_attr_autosuspend.attr, + power_group); + return rc; +} + +static void remove_power_attributes(struct device *dev) +{ + sysfs_remove_file_from_group(&dev->kobj, + &dev_attr_autosuspend.attr, + power_group); +} + +#else + +#define add_power_attributes(dev) 0 +#define remove_power_attributes(dev) do {} while (0) + +#endif /* CONFIG_USB_SUSPEND */ + /* Descriptor fields */ #define usb_descriptor_attr_le16(field, format_string) \ static ssize_t \ @@ -204,6 +273,7 @@ static struct attribute *dev_attrs[] = { &dev_attr_devnum.attr, &dev_attr_version.attr, &dev_attr_maxchild.attr, + &dev_attr_quirks.attr, NULL, }; static struct attribute_group dev_attr_grp = { @@ -219,6 +289,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev) if (retval) return retval; + retval = add_power_attributes(dev); + if (retval) + goto error; + if (udev->manufacturer) { retval = device_create_file(dev, &dev_attr_manufacturer); if (retval) @@ -239,10 +313,7 @@ int usb_create_sysfs_dev_files(struct usb_device *udev) goto error; return 0; error: - usb_remove_ep_files(&udev->ep0); - device_remove_file(dev, &dev_attr_manufacturer); - device_remove_file(dev, &dev_attr_product); - device_remove_file(dev, &dev_attr_serial); + usb_remove_sysfs_dev_files(udev); return retval; } @@ -251,14 +322,11 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev) struct device *dev = &udev->dev; usb_remove_ep_files(&udev->ep0); + device_remove_file(dev, &dev_attr_manufacturer); + device_remove_file(dev, &dev_attr_product); + device_remove_file(dev, &dev_attr_serial); + remove_power_attributes(dev); sysfs_remove_group(&dev->kobj, &dev_attr_grp); - - if (udev->manufacturer) - device_remove_file(dev, &dev_attr_manufacturer); - if (udev->product) - device_remove_file(dev, &dev_attr_product); - if (udev->serial) - device_remove_file(dev, &dev_attr_serial); } /* Interface fields */ @@ -362,33 +430,28 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf) int usb_create_sysfs_intf_files(struct usb_interface *intf) { + struct device *dev = &intf->dev; struct usb_device *udev = interface_to_usbdev(intf); struct usb_host_interface *alt = intf->cur_altsetting; int retval; - retval = sysfs_create_group(&intf->dev.kobj, &intf_attr_grp); + retval = sysfs_create_group(&dev->kobj, &intf_attr_grp); if (retval) - goto error; + return retval; if (alt->string == NULL) alt->string = usb_cache_string(udev, alt->desc.iInterface); if (alt->string) - retval = device_create_file(&intf->dev, &dev_attr_interface); + retval = device_create_file(dev, &dev_attr_interface); usb_create_intf_ep_files(intf, udev); return 0; -error: - if (alt->string) - device_remove_file(&intf->dev, &dev_attr_interface); - sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); - usb_remove_intf_ep_files(intf); - return retval; } void usb_remove_sysfs_intf_files(struct usb_interface *intf) { - usb_remove_intf_ep_files(intf); - sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp); + struct device *dev = &intf->dev; - if (intf->cur_altsetting->string) - device_remove_file(&intf->dev, &dev_attr_interface); + usb_remove_intf_ep_files(intf); + device_remove_file(dev, &dev_attr_interface); + sysfs_remove_group(&dev->kobj, &intf_attr_grp); } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 3db721cd557..54b42ce311c 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -22,6 +22,7 @@ */ #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/string.h> #include <linux/bitops.h> #include <linux/slab.h> @@ -50,6 +51,16 @@ static int nousb; /* Disable USB when built into kernel image */ struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */ +#ifdef CONFIG_USB_SUSPEND +static int usb_autosuspend_delay = 2; /* Default delay value, + * in seconds */ +module_param_named(autosuspend, usb_autosuspend_delay, uint, 0644); +MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); + +#else +#define usb_autosuspend_delay 0 +#endif + /** * usb_ifnum_to_if - get the interface object with a given interface number @@ -306,6 +317,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) #ifdef CONFIG_PM mutex_init(&dev->pm_mutex); INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); + dev->autosuspend_delay = usb_autosuspend_delay * HZ; #endif return dev; } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 17830a81be1..08b5a04e375 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -13,6 +13,7 @@ extern void usb_disable_interface (struct usb_device *dev, struct usb_interface *intf); extern void usb_release_interface_cache(struct kref *ref); extern void usb_disable_device (struct usb_device *dev, int skip_ep0); +extern void usb_detect_quirks(struct usb_device *udev); extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); @@ -21,6 +22,8 @@ extern int usb_set_configuration(struct usb_device *dev, int configuration); extern void usb_kick_khubd(struct usb_device *dev); extern void usb_resume_root_hub(struct usb_device *dev); +extern int usb_match_device(struct usb_device *dev, + const struct usb_device_id *id); extern int usb_hub_init(void); extern void usb_hub_cleanup(void); @@ -62,14 +65,14 @@ static inline void usb_pm_unlock(struct usb_device *udev) {} #ifdef CONFIG_USB_SUSPEND -#define USB_AUTOSUSPEND_DELAY (HZ*2) - extern void usb_autosuspend_device(struct usb_device *udev); +extern void usb_try_autosuspend_device(struct usb_device *udev); extern int usb_autoresume_device(struct usb_device *udev); #else -#define usb_autosuspend_device(udev) do {} while (0) +#define usb_autosuspend_device(udev) do {} while (0) +#define usb_try_autosuspend_device(udev) do {} while (0) static inline int usb_autoresume_device(struct usb_device *udev) { return 0; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 34296e79edc..188c74a9521 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -553,6 +553,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) { struct kiocb_priv *priv = iocb->private; ssize_t len, total; + void *to_copy; int i; /* we "retry" to get the right mm context for this: */ @@ -560,10 +561,11 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) /* copy stuff into user buffers */ total = priv->actual; len = 0; + to_copy = priv->buf; for (i=0; i < priv->nr_segs; i++) { ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total); - if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) { + if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) { if (len == 0) len = -EFAULT; break; @@ -571,6 +573,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb) total -= this; len += this; + to_copy += this; if (total == 0) break; } diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 5d6c06bc452..8d24d3dc0a6 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -196,7 +196,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) struct uhci_td *td = list_entry(urbp->td_list.next, struct uhci_td, list); - if (cpu_to_le32(td->dma_handle) != (element & ~UHCI_PTR_BITS)) + if (element != LINK_TO_TD(td)) out += sprintf(out, "%*s Element != First TD\n", space, ""); i = nurbs = 0; @@ -220,16 +220,6 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space) return out - buf; } -static const char * const qh_names[] = { - "skel_unlink_qh", "skel_iso_qh", - "skel_int128_qh", "skel_int64_qh", - "skel_int32_qh", "skel_int16_qh", - "skel_int8_qh", "skel_int4_qh", - "skel_int2_qh", "skel_int1_qh", - "skel_ls_control_qh", "skel_fs_control_qh", - "skel_bulk_qh", "skel_term_qh" -}; - static int uhci_show_sc(int port, unsigned short status, char *buf, int len) { char *out = buf; @@ -352,6 +342,12 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) struct uhci_td *td; struct list_head *tmp, *head; int nframes, nerrs; + __le32 link; + + static const char * const qh_names[] = { + "unlink", "iso", "int128", "int64", "int32", "int16", + "int8", "int4", "int2", "async", "term" + }; out += uhci_show_root_hub_state(uhci, out, len - (out - buf)); out += sprintf(out, "HC status\n"); @@ -374,7 +370,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) nframes = 10; nerrs = 0; for (i = 0; i < UHCI_NUMFRAMES; ++i) { - __le32 link, qh_dma; + __le32 qh_dma; j = 0; td = uhci->frame_cpu[i]; @@ -393,7 +389,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len) do { td = list_entry(tmp, struct uhci_td, fl_list); tmp = tmp->next; - if (cpu_to_le32(td->dma_handle) != link) { + if (link != LINK_TO_TD(td)) { if (nframes > 0) out += sprintf(out, " link does " "not match list entry!\n"); @@ -430,23 +426,21 @@ check_link: for (i = 0; i < UHCI_NUM_SKELQH; ++i) { int cnt = 0; + __le32 fsbr_link = 0; qh = uhci->skelqh[i]; - out += sprintf(out, "- %s\n", qh_names[i]); \ + out += sprintf(out, "- skel_%s_qh\n", qh_names[i]); \ out += uhci_show_qh(qh, out, len - (out - buf), 4); /* Last QH is the Terminating QH, it's different */ - if (i == UHCI_NUM_SKELQH - 1) { - if (qh->link != UHCI_PTR_TERM) - out += sprintf(out, " bandwidth reclamation on!\n"); - - if (qh_element(qh) != cpu_to_le32(uhci->term_td->dma_handle)) + if (i == SKEL_TERM) { + if (qh_element(qh) != LINK_TO_TD(uhci->term_td)) out += sprintf(out, " skel_term_qh element is not set to term_td!\n"); - + if (link == LINK_TO_QH(uhci->skel_term_qh)) + goto check_qh_link; continue; } - j = (i < 9) ? 9 : i+1; /* Next skeleton */ head = &qh->node; tmp = head->next; @@ -456,15 +450,26 @@ check_link: if (++cnt <= 10) out += uhci_show_qh(qh, out, len - (out - buf), 4); + if (!fsbr_link && qh->skel >= SKEL_FSBR) + fsbr_link = LINK_TO_QH(qh); } if ((cnt -= 10) > 0) out += sprintf(out, " Skipped %d QHs\n", cnt); - if (i > 1 && i < UHCI_NUM_SKELQH - 1) { - if (qh->link != - (cpu_to_le32(uhci->skelqh[j]->dma_handle) | UHCI_PTR_QH)) - out += sprintf(out, " last QH not linked to next skeleton!\n"); - } + link = UHCI_PTR_TERM; + if (i <= SKEL_ISO) + ; + else if (i < SKEL_ASYNC) + link = LINK_TO_QH(uhci->skel_async_qh); + else if (!uhci->fsbr_is_on) + ; + else if (fsbr_link) + link = fsbr_link; + else + link = LINK_TO_QH(uhci->skel_term_qh); +check_qh_link: + if (qh->link != link) + out += sprintf(out, " last QH not linked to next skeleton!\n"); } return out - buf; diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index ded4df30a63..44da4334f1d 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -13,7 +13,7 @@ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) - * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu + * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu * * Intel documents this fairly well, and as far as I know there * are no royalties or anything like that, but even so there are @@ -107,16 +107,16 @@ static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame) * interrupt QHs, which will help spread out bandwidth utilization. * * ffs (Find First bit Set) does exactly what we need: - * 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8], - * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc. + * 1,3,5,... => ffs = 0 => use period-2 QH = skelqh[8], + * 2,6,10,... => ffs = 1 => use period-4 QH = skelqh[7], etc. * ffs >= 7 => not on any high-period queue, so use - * skel_int1_qh = skelqh[9]. + * period-1 QH = skelqh[9]. * Add in UHCI_NUMFRAMES to insure at least one bit is set. */ skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES); if (skelnum <= 1) skelnum = 9; - return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle); + return LINK_TO_QH(uhci->skelqh[skelnum]); } #include "uhci-debug.c" @@ -540,16 +540,18 @@ static void uhci_shutdown(struct pci_dev *pdev) * * The hardware doesn't really know any difference * in the queues, but the order does matter for the - * protocols higher up. The order is: + * protocols higher up. The order in which the queues + * are encountered by the hardware is: * - * - any isochronous events handled before any + * - All isochronous events are handled before any * of the queues. We don't do that here, because * we'll create the actual TD entries on demand. - * - The first queue is the interrupt queue. - * - The second queue is the control queue, split into low- and full-speed - * - The third queue is bulk queue. - * - The fourth queue is the bandwidth reclamation queue, which loops back - * to the full-speed control queue. + * - The first queue is the high-period interrupt queue. + * - The second queue is the period-1 interrupt and async + * (low-speed control, full-speed control, then bulk) queue. + * - The third queue is the terminating bandwidth reclamation queue, + * which contains no members, loops back to itself, and is present + * only when FSBR is on and there are no full-speed control or bulk QHs. */ static int uhci_start(struct usb_hcd *hcd) { @@ -626,34 +628,18 @@ static int uhci_start(struct usb_hcd *hcd) } /* - * 8 Interrupt queues; link all higher int queues to int1, - * then link int1 to control and control to bulk + * 8 Interrupt queues; link all higher int queues to int1 = async */ - uhci->skel_int128_qh->link = - uhci->skel_int64_qh->link = - uhci->skel_int32_qh->link = - uhci->skel_int16_qh->link = - uhci->skel_int8_qh->link = - uhci->skel_int4_qh->link = - uhci->skel_int2_qh->link = UHCI_PTR_QH | - cpu_to_le32(uhci->skel_int1_qh->dma_handle); - - uhci->skel_int1_qh->link = UHCI_PTR_QH | - cpu_to_le32(uhci->skel_ls_control_qh->dma_handle); - uhci->skel_ls_control_qh->link = UHCI_PTR_QH | - cpu_to_le32(uhci->skel_fs_control_qh->dma_handle); - uhci->skel_fs_control_qh->link = UHCI_PTR_QH | - cpu_to_le32(uhci->skel_bulk_qh->dma_handle); - uhci->skel_bulk_qh->link = UHCI_PTR_QH | - cpu_to_le32(uhci->skel_term_qh->dma_handle); + for (i = SKEL_ISO + 1; i < SKEL_ASYNC; ++i) + uhci->skelqh[i]->link = LINK_TO_QH(uhci->skel_async_qh); + uhci->skel_async_qh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM; /* This dummy TD is to work around a bug in Intel PIIX controllers */ uhci_fill_td(uhci->term_td, 0, uhci_explen(0) | - (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0); - uhci->term_td->link = cpu_to_le32(uhci->term_td->dma_handle); - - uhci->skel_term_qh->link = UHCI_PTR_TERM; - uhci->skel_term_qh->element = cpu_to_le32(uhci->term_td->dma_handle); + (0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0); + uhci->term_td->link = UHCI_PTR_TERM; + uhci->skel_async_qh->element = uhci->skel_term_qh->element = + LINK_TO_TD(uhci->term_td); /* * Fill the frame list: make all entries point to the proper diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 74469b5bcb6..1b3d23406ac 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -129,11 +129,12 @@ struct uhci_qh { __le32 element; /* Queue element (TD) pointer */ /* Software fields */ + dma_addr_t dma_handle; + struct list_head node; /* Node in the list of QHs */ struct usb_host_endpoint *hep; /* Endpoint information */ struct usb_device *udev; struct list_head queue; /* Queue of urbps for this QH */ - struct uhci_qh *skel; /* Skeleton for this QH */ struct uhci_td *dummy_td; /* Dummy TD to end the queue */ struct uhci_td *post_td; /* Last TD completed */ @@ -149,8 +150,7 @@ struct uhci_qh { int state; /* QH_STATE_xxx; see above */ int type; /* Queue type (control, bulk, etc) */ - - dma_addr_t dma_handle; + int skel; /* Skeleton queue number */ unsigned int initial_toggle:1; /* Endpoint's current toggle value */ unsigned int needs_fixup:1; /* Must fix the TD toggle values */ @@ -171,6 +171,8 @@ static inline __le32 qh_element(struct uhci_qh *qh) { return element; } +#define LINK_TO_QH(qh) (UHCI_PTR_QH | cpu_to_le32((qh)->dma_handle)) + /* * Transfer Descriptors @@ -264,6 +266,8 @@ static inline u32 td_status(struct uhci_td *td) { return le32_to_cpu(status); } +#define LINK_TO_TD(td) (cpu_to_le32((td)->dma_handle)) + /* * Skeleton Queue Headers @@ -272,12 +276,13 @@ static inline u32 td_status(struct uhci_td *td) { /* * The UHCI driver uses QHs with Interrupt, Control and Bulk URBs for * automatic queuing. To make it easy to insert entries into the schedule, - * we have a skeleton of QHs for each predefined Interrupt latency, - * low-speed control, full-speed control, bulk, and terminating QH - * (see explanation for the terminating QH below). + * we have a skeleton of QHs for each predefined Interrupt latency. + * Asynchronous QHs (low-speed control, full-speed control, and bulk) + * go onto the period-1 interrupt list, since they all get accessed on + * every frame. * - * When we want to add a new QH, we add it to the end of the list for the - * skeleton QH. For instance, the schedule list can look like this: + * When we want to add a new QH, we add it to the list starting from the + * appropriate skeleton QH. For instance, the schedule can look like this: * * skel int128 QH * dev 1 interrupt QH @@ -285,50 +290,47 @@ static inline u32 td_status(struct uhci_td *td) { * skel int64 QH * skel int32 QH * ... - * skel int1 QH - * skel low-speed control QH - * dev 5 control QH - * skel full-speed control QH - * skel bulk QH + * skel int1 + async QH + * dev 5 low-speed control QH * dev 1 bulk QH * dev 2 bulk QH - * skel terminating QH * - * The terminating QH is used for 2 reasons: - * - To place a terminating TD which is used to workaround a PIIX bug - * (see Intel errata for explanation), and - * - To loop back to the full-speed control queue for full-speed bandwidth - * reclamation. + * There is a special terminating QH used to keep full-speed bandwidth + * reclamation active when no full-speed control or bulk QHs are linked + * into the schedule. It has an inactive TD (to work around a PIIX bug, + * see the Intel errata) and it points back to itself. * - * There's a special skeleton QH for Isochronous QHs. It never appears - * on the schedule, and Isochronous TDs go on the schedule before the + * There's a special skeleton QH for Isochronous QHs which never appears + * on the schedule. Isochronous TDs go on the schedule before the * the skeleton QHs. The hardware accesses them directly rather than * through their QH, which is used only for bookkeeping purposes. * While the UHCI spec doesn't forbid the use of QHs for Isochronous, * it doesn't use them either. And the spec says that queues never * advance on an error completion status, which makes them totally * unsuitable for Isochronous transfers. + * + * There's also a special skeleton QH used for QHs which are in the process + * of unlinking and so may still be in use by the hardware. It too never + * appears on the schedule. */ -#define UHCI_NUM_SKELQH 14 -#define skel_unlink_qh skelqh[0] -#define skel_iso_qh skelqh[1] -#define skel_int128_qh skelqh[2] -#define skel_int64_qh skelqh[3] -#define skel_int32_qh skelqh[4] -#define skel_int16_qh skelqh[5] -#define skel_int8_qh skelqh[6] -#define skel_int4_qh skelqh[7] -#define skel_int2_qh skelqh[8] -#define skel_int1_qh skelqh[9] -#define skel_ls_control_qh skelqh[10] -#define skel_fs_control_qh skelqh[11] -#define skel_bulk_qh skelqh[12] -#define skel_term_qh skelqh[13] - -/* Find the skelqh entry corresponding to an interval exponent */ -#define UHCI_SKEL_INDEX(exponent) (9 - exponent) - +#define UHCI_NUM_SKELQH 11 +#define SKEL_UNLINK 0 +#define skel_unlink_qh skelqh[SKEL_UNLINK] +#define SKEL_ISO 1 +#define skel_iso_qh skelqh[SKEL_ISO] + /* int128, int64, ..., int1 = 2, 3, ..., 9 */ +#define SKEL_INDEX(exponent) (9 - exponent) +#define SKEL_ASYNC 9 +#define skel_async_qh skelqh[SKEL_ASYNC] +#define SKEL_TERM 10 +#define skel_term_qh skelqh[SKEL_TERM] + +/* The following entries refer to sublists of skel_async_qh */ +#define SKEL_LS_CONTROL 20 +#define SKEL_FS_CONTROL 21 +#define SKEL_FSBR SKEL_FS_CONTROL +#define SKEL_BULK 22 /* * The UHCI controller and root hub diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 68e66b33e72..f4ebdb3e488 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -13,7 +13,7 @@ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) - * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu + * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu */ @@ -45,15 +45,43 @@ static inline void uhci_clear_next_interrupt(struct uhci_hcd *uhci) */ static void uhci_fsbr_on(struct uhci_hcd *uhci) { + struct uhci_qh *fsbr_qh, *lqh, *tqh; + uhci->fsbr_is_on = 1; - uhci->skel_term_qh->link = cpu_to_le32( - uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH; + lqh = list_entry(uhci->skel_async_qh->node.prev, + struct uhci_qh, node); + + /* Find the first FSBR QH. Linear search through the list is + * acceptable because normally FSBR gets turned on as soon as + * one QH needs it. */ + fsbr_qh = NULL; + list_for_each_entry_reverse(tqh, &uhci->skel_async_qh->node, node) { + if (tqh->skel < SKEL_FSBR) + break; + fsbr_qh = tqh; + } + + /* No FSBR QH means we must insert the terminating skeleton QH */ + if (!fsbr_qh) { + uhci->skel_term_qh->link = LINK_TO_QH(uhci->skel_term_qh); + wmb(); + lqh->link = uhci->skel_term_qh->link; + + /* Otherwise loop the last QH to the first FSBR QH */ + } else + lqh->link = LINK_TO_QH(fsbr_qh); } static void uhci_fsbr_off(struct uhci_hcd *uhci) { + struct uhci_qh *lqh; + uhci->fsbr_is_on = 0; - uhci->skel_term_qh->link = UHCI_PTR_TERM; + lqh = list_entry(uhci->skel_async_qh->node.prev, + struct uhci_qh, node); + + /* End the async list normally and unlink the terminating QH */ + lqh->link = uhci->skel_term_qh->link = UHCI_PTR_TERM; } static void uhci_add_fsbr(struct uhci_hcd *uhci, struct urb *urb) @@ -158,11 +186,11 @@ static inline void uhci_insert_td_in_frame_list(struct uhci_hcd *uhci, td->link = ltd->link; wmb(); - ltd->link = cpu_to_le32(td->dma_handle); + ltd->link = LINK_TO_TD(td); } else { td->link = uhci->frame[framenum]; wmb(); - uhci->frame[framenum] = cpu_to_le32(td->dma_handle); + uhci->frame[framenum] = LINK_TO_TD(td); uhci->frame_cpu[framenum] = td; } } @@ -184,7 +212,7 @@ static inline void uhci_remove_td_from_frame_list(struct uhci_hcd *uhci, struct uhci_td *ntd; ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list); - uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle); + uhci->frame[td->frame] = LINK_TO_TD(ntd); uhci->frame_cpu[td->frame] = ntd; } } else { @@ -405,12 +433,81 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first) } /* - * Put a QH on the schedule in both hardware and software + * Link an Isochronous QH into its skeleton's list */ -static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) +static inline void link_iso(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + list_add_tail(&qh->node, &uhci->skel_iso_qh->node); + + /* Isochronous QHs aren't linked by the hardware */ +} + +/* + * Link a high-period interrupt QH into the schedule at the end of its + * skeleton's list + */ +static void link_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh) { struct uhci_qh *pqh; + list_add_tail(&qh->node, &uhci->skelqh[qh->skel]->node); + + pqh = list_entry(qh->node.prev, struct uhci_qh, node); + qh->link = pqh->link; + wmb(); + pqh->link = LINK_TO_QH(qh); +} + +/* + * Link a period-1 interrupt or async QH into the schedule at the + * correct spot in the async skeleton's list, and update the FSBR link + */ +static void link_async(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + struct uhci_qh *pqh, *lqh; + __le32 link_to_new_qh; + __le32 *extra_link = &link_to_new_qh; + + /* Find the predecessor QH for our new one and insert it in the list. + * The list of QHs is expected to be short, so linear search won't + * take too long. */ + list_for_each_entry_reverse(pqh, &uhci->skel_async_qh->node, node) { + if (pqh->skel <= qh->skel) + break; + } + list_add(&qh->node, &pqh->node); + qh->link = pqh->link; + + link_to_new_qh = LINK_TO_QH(qh); + + /* If this is now the first FSBR QH, take special action */ + if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR && + qh->skel >= SKEL_FSBR) { + lqh = list_entry(uhci->skel_async_qh->node.prev, + struct uhci_qh, node); + + /* If the new QH is also the last one, we must unlink + * the terminating skeleton QH and make the new QH point + * back to itself. */ + if (qh == lqh) { + qh->link = link_to_new_qh; + extra_link = &uhci->skel_term_qh->link; + + /* Otherwise the last QH must point to the new QH */ + } else + extra_link = &lqh->link; + } + + /* Link it into the schedule */ + wmb(); + *extra_link = pqh->link = link_to_new_qh; +} + +/* + * Put a QH on the schedule in both hardware and software + */ +static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ WARN_ON(list_empty(&qh->queue)); /* Set the element pointer if it isn't set already. @@ -421,7 +518,7 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) struct uhci_td *td = list_entry(urbp->td_list.next, struct uhci_td, list); - qh->element = cpu_to_le32(td->dma_handle); + qh->element = LINK_TO_TD(td); } /* Treat the queue as if it has just advanced */ @@ -432,18 +529,64 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) return; qh->state = QH_STATE_ACTIVE; - /* Move the QH from its old list to the end of the appropriate + /* Move the QH from its old list to the correct spot in the appropriate * skeleton's list */ if (qh == uhci->next_qh) uhci->next_qh = list_entry(qh->node.next, struct uhci_qh, node); - list_move_tail(&qh->node, &qh->skel->node); + list_del(&qh->node); + + if (qh->skel == SKEL_ISO) + link_iso(uhci, qh); + else if (qh->skel < SKEL_ASYNC) + link_interrupt(uhci, qh); + else + link_async(uhci, qh); +} + +/* + * Unlink a high-period interrupt QH from the schedule + */ +static void unlink_interrupt(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + struct uhci_qh *pqh; - /* Link it into the schedule */ pqh = list_entry(qh->node.prev, struct uhci_qh, node); - qh->link = pqh->link; - wmb(); - pqh->link = UHCI_PTR_QH | cpu_to_le32(qh->dma_handle); + pqh->link = qh->link; + mb(); +} + +/* + * Unlink a period-1 interrupt or async QH from the schedule + */ +static void unlink_async(struct uhci_hcd *uhci, struct uhci_qh *qh) +{ + struct uhci_qh *pqh, *lqh; + __le32 link_to_next_qh = qh->link; + + pqh = list_entry(qh->node.prev, struct uhci_qh, node); + + /* If this is the first FSBQ QH, take special action */ + if (uhci->fsbr_is_on && pqh->skel < SKEL_FSBR && + qh->skel >= SKEL_FSBR) { + lqh = list_entry(uhci->skel_async_qh->node.prev, + struct uhci_qh, node); + + /* If this QH is also the last one, we must link in + * the terminating skeleton QH. */ + if (qh == lqh) { + link_to_next_qh = LINK_TO_QH(uhci->skel_term_qh); + uhci->skel_term_qh->link = link_to_next_qh; + wmb(); + qh->link = link_to_next_qh; + + /* Otherwise the last QH must point to the new first FSBR QH */ + } else + lqh->link = link_to_next_qh; + } + + pqh->link = link_to_next_qh; + mb(); } /* @@ -451,17 +594,18 @@ static void uhci_activate_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) */ static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh) { - struct uhci_qh *pqh; - if (qh->state == QH_STATE_UNLINKING) return; WARN_ON(qh->state != QH_STATE_ACTIVE || !qh->udev); qh->state = QH_STATE_UNLINKING; /* Unlink the QH from the schedule and record when we did it */ - pqh = list_entry(qh->node.prev, struct uhci_qh, node); - pqh->link = qh->link; - mb(); + if (qh->skel == SKEL_ISO) + ; + else if (qh->skel < SKEL_ASYNC) + unlink_interrupt(uhci, qh); + else + unlink_async(uhci, qh); uhci_get_current_frame_number(uhci); qh->unlink_frame = uhci->frame_number; @@ -697,6 +841,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, dma_addr_t data = urb->transfer_dma; __le32 *plink; struct urb_priv *urbp = urb->hcpriv; + int skel; /* The "pipe" thing contains the destination in bits 8--18 */ destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; @@ -737,7 +882,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, td = uhci_alloc_td(uhci); if (!td) goto nomem; - *plink = cpu_to_le32(td->dma_handle); + *plink = LINK_TO_TD(td); /* Alternate Data0/1 (start with Data1) */ destination ^= TD_TOKEN_TOGGLE; @@ -757,7 +902,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, td = uhci_alloc_td(uhci); if (!td) goto nomem; - *plink = cpu_to_le32(td->dma_handle); + *plink = LINK_TO_TD(td); /* * It's IN if the pipe is an output pipe or we're not expecting @@ -784,7 +929,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, td = uhci_alloc_td(uhci); if (!td) goto nomem; - *plink = cpu_to_le32(td->dma_handle); + *plink = LINK_TO_TD(td); uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0); wmb(); @@ -797,11 +942,13 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, * isn't in the CONFIGURED state. */ if (urb->dev->speed == USB_SPEED_LOW || urb->dev->state != USB_STATE_CONFIGURED) - qh->skel = uhci->skel_ls_control_qh; + skel = SKEL_LS_CONTROL; else { - qh->skel = uhci->skel_fs_control_qh; + skel = SKEL_FS_CONTROL; uhci_add_fsbr(uhci, urb); } + if (qh->state != QH_STATE_ACTIVE) + qh->skel = skel; urb->actual_length = -8; /* Account for the SETUP packet */ return 0; @@ -860,7 +1007,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, td = uhci_alloc_td(uhci); if (!td) goto nomem; - *plink = cpu_to_le32(td->dma_handle); + *plink = LINK_TO_TD(td); } uhci_add_td_to_urbp(td, urbp); uhci_fill_td(td, status, @@ -888,7 +1035,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, td = uhci_alloc_td(uhci); if (!td) goto nomem; - *plink = cpu_to_le32(td->dma_handle); + *plink = LINK_TO_TD(td); uhci_add_td_to_urbp(td, urbp); uhci_fill_td(td, status, @@ -914,7 +1061,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, td = uhci_alloc_td(uhci); if (!td) goto nomem; - *plink = cpu_to_le32(td->dma_handle); + *plink = LINK_TO_TD(td); uhci_fill_td(td, 0, USB_PID_OUT | uhci_explen(0), 0); wmb(); @@ -931,7 +1078,7 @@ nomem: return -ENOMEM; } -static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, +static int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct uhci_qh *qh) { int ret; @@ -940,7 +1087,8 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, if (urb->dev->speed == USB_SPEED_LOW) return -EINVAL; - qh->skel = uhci->skel_bulk_qh; + if (qh->state != QH_STATE_ACTIVE) + qh->skel = SKEL_BULK; ret = uhci_submit_common(uhci, urb, qh); if (ret == 0) uhci_add_fsbr(uhci, urb); @@ -968,7 +1116,7 @@ static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, if (exponent < 0) return -EINVAL; qh->period = 1 << exponent; - qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)]; + qh->skel = SKEL_INDEX(exponent); /* For now, interrupt phase is fixed by the layout * of the QH lists. */ @@ -1005,7 +1153,7 @@ static int uhci_fixup_short_transfer(struct uhci_hcd *uhci, * the queue at the status stage transaction, which is * the last TD. */ WARN_ON(list_empty(&urbp->td_list)); - qh->element = cpu_to_le32(td->dma_handle); + qh->element = LINK_TO_TD(td); tmp = td->list.prev; ret = -EINPROGRESS; @@ -1216,7 +1364,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb, qh->iso_status = 0; } - qh->skel = uhci->skel_iso_qh; + qh->skel = SKEL_ISO; if (!qh->bandwidth_reserved) uhci_reserve_bandwidth(uhci, qh); return 0; @@ -1566,8 +1714,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh) if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) { /* Detect the Intel bug and work around it */ - if (qh->post_td && qh_element(qh) == - cpu_to_le32(qh->post_td->dma_handle)) { + if (qh->post_td && qh_element(qh) == LINK_TO_TD(qh->post_td)) { qh->element = qh->post_td->link; qh->advance_jiffies = jiffies; ret = 1; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index ef09952f203..827a75a186b 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -4,7 +4,7 @@ * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc - * Copyright (c) 2006 Jiri Kosina + * Copyright (c) 2006-2007 Jiri Kosina */ /* @@ -27,9 +27,6 @@ #include <linux/input.h> #include <linux/wait.h> -#undef DEBUG -#undef DEBUG_DATA - #include <linux/usb.h> #include <linux/hid.h> @@ -689,10 +686,8 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802 #define USB_VENDOR_ID_CODEMERCS 0x07c0 -#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 -#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 -#define USB_DEVICE_ID_CODEMERCS_IOW48 0x1502 -#define USB_DEVICE_ID_CODEMERCS_IOW28 0x1503 +#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 +#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff #define USB_VENDOR_ID_DELORME 0x1163 #define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 @@ -758,6 +753,8 @@ void usbhid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_LOGITECH 0x046d #define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 +#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2 0xc517 +#define USB_DEVICE_ID_DINOVO_EDGE 0xc714 #define USB_VENDOR_ID_IMATION 0x0718 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 @@ -778,6 +775,8 @@ static const struct hid_blacklist { unsigned quirks; } hid_blacklist[] = { + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES }, + { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE }, @@ -788,10 +787,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW48, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE }, @@ -944,6 +939,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, @@ -1041,6 +1037,22 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum) kfree(buf); } +/* + * Logitech S510 keyboard sends in report #3 keys which are far + * above the logical maximum described in descriptor. This extends + * the original value of 0x28c of logical maximum to 0x104d + */ +static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize) +{ + if (rsize >= 90 && rdesc[83] == 0x26 + && rdesc[84] == 0x8c + && rdesc[85] == 0x02) { + info("Fixing up Logitech S510 report descriptor"); + rdesc[84] = rdesc[89] = 0x4d; + rdesc[85] = rdesc[90] = 0x10; + } +} + static struct hid_device *usb_hid_configure(struct usb_interface *intf) { struct usb_host_interface *interface = intf->cur_altsetting; @@ -1052,9 +1064,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) int n, len, insize = 0; struct usbhid_device *usbhid; - /* Ignore all Wacom devices */ - if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM) - return NULL; + /* Ignore all Wacom devices */ + if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM) + return NULL; + /* ignore all Code Mercenaries IOWarrior devices */ + if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_CODEMERCS) + if (le16_to_cpu(dev->descriptor.idProduct) >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST && + le16_to_cpu(dev->descriptor.idProduct) <= USB_DEVICE_ID_CODEMERCS_IOW_LAST) + return NULL; for (n = 0; hid_blacklist[n].idVendor; n++) if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) && @@ -1109,7 +1126,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if ((quirks & HID_QUIRK_CYMOTION)) hid_fixup_cymotion_descriptor(rdesc, rsize); -#ifdef DEBUG_DATA + if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR) + hid_fixup_s510_descriptor(rdesc, rsize); + +#ifdef CONFIG_HID_DEBUG printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); for (n = 0; n < rsize; n++) printk(" %02x", (unsigned char) rdesc[n]); @@ -1225,8 +1245,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) le16_to_cpu(dev->descriptor.idProduct)); hid->bus = BUS_USB; - hid->vendor = dev->descriptor.idVendor; - hid->product = dev->descriptor.idProduct; + hid->vendor = le16_to_cpu(dev->descriptor.idVendor); + hid->product = le16_to_cpu(dev->descriptor.idProduct); usb_make_path(dev, hid->phys, sizeof(hid->phys)); strlcat(hid->phys, "/input", sizeof(hid->phys)); diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index 8505824848f..3749f4a235f 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -31,6 +31,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/usb/input.h> +#include <linux/hid.h> /* * Version Information @@ -330,7 +331,8 @@ static void usb_kbd_disconnect(struct usb_interface *intf) } static struct usb_device_id usb_kbd_id_table [] = { - { USB_INTERFACE_INFO(3, 1, 1) }, + { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, + USB_INTERFACE_PROTOCOL_KEYBOARD) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index 64a33e420cf..692fd608777 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -31,6 +31,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/usb/input.h> +#include <linux/hid.h> /* * Version Information @@ -213,7 +214,8 @@ static void usb_mouse_disconnect(struct usb_interface *intf) } static struct usb_device_id usb_mouse_id_table [] = { - { USB_INTERFACE_INFO(3, 1, 2) }, + { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT, + USB_INTERFACE_PROTOCOL_MOUSE) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c index 4142e36730f..4f3e9bc7177 100644 --- a/drivers/usb/input/wacom_wac.c +++ b/drivers/usb/input/wacom_wac.c @@ -163,7 +163,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) } id = STYLUS_DEVICE_ID; - if (data[1] & 0x10) { /* in prox */ + if (data[1] & 0x80) { /* in prox */ switch ((data[1] >> 5) & 3) { @@ -196,9 +196,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f); break; } - } - - if (data[1] & 0x90) { x = wacom_le16_to_cpu(&data[2]); y = wacom_le16_to_cpu(&data[4]); wacom_report_abs(wcombo, ABS_X, x); @@ -210,19 +207,28 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04); } wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */ - } - else - wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ - - if (data[1] & 0x10) /* only report prox-in when in area */ wacom_report_key(wcombo, wacom->tool[0], 1); - if (!(data[1] & 0x90)) /* report prox-out when physically out */ + } else if (!(data[1] & 0x90)) { + wacom_report_abs(wcombo, ABS_X, 0); + wacom_report_abs(wcombo, ABS_Y, 0); + if (wacom->tool[0] == BTN_TOOL_MOUSE) { + wacom_report_key(wcombo, BTN_LEFT, 0); + wacom_report_key(wcombo, BTN_RIGHT, 0); + wacom_report_abs(wcombo, ABS_DISTANCE, 0); + } else { + wacom_report_abs(wcombo, ABS_PRESSURE, 0); + wacom_report_key(wcombo, BTN_TOUCH, 0); + wacom_report_key(wcombo, BTN_STYLUS, 0); + wacom_report_key(wcombo, BTN_STYLUS2, 0); + } + wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ wacom_report_key(wcombo, wacom->tool[0], 0); - wacom_input_sync(wcombo); + } /* send pad data */ if (wacom->features->type == WACOM_G4) { - if ( (wacom->serial[1] & 0xc0) != (data[7] & 0xf8) ) { + if (data[7] & 0xf8) { + wacom_input_sync(wcombo); /* sync last event */ wacom->id[1] = 1; wacom->serial[1] = (data[7] & 0xf8); wacom_report_key(wcombo, BTN_0, (data[7] & 0x40)); @@ -230,10 +236,15 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); wacom_report_rel(wcombo, REL_WHEEL, rw); wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0); + wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); } else if (wacom->id[1]) { + wacom_input_sync(wcombo); /* sync last event */ wacom->id[1] = 0; + wacom_report_key(wcombo, BTN_0, (data[7] & 0x40)); + wacom_report_key(wcombo, BTN_4, (data[7] & 0x80)); wacom_report_key(wcombo, BTN_TOOL_FINGER, 0); + wacom_report_abs(wcombo, ABS_MISC, 0); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0); } } @@ -304,28 +315,35 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) default: /* Unknown tool */ wacom->tool[idx] = BTN_TOOL_PEN; } - /* only large I3 support Lens Cursor */ - if(!((wacom->tool[idx] == BTN_TOOL_LENS) - && ((wacom->features->type == INTUOS3) - || (wacom->features->type == INTUOS3S)))) { - wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */ - wacom_report_key(wcombo, wacom->tool[idx], 1); - wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - return 2; - } return 1; } /* Exit report */ if ((data[1] & 0xfe) == 0x80) { - if(!((wacom->tool[idx] == BTN_TOOL_LENS) - && ((wacom->features->type == INTUOS3) - || (wacom->features->type == INTUOS3S)))) { - wacom_report_key(wcombo, wacom->tool[idx], 0); - wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ - wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - return 2; + wacom_report_abs(wcombo, ABS_X, 0); + wacom_report_abs(wcombo, ABS_Y, 0); + wacom_report_abs(wcombo, ABS_DISTANCE, 0); + if (wacom->tool[idx] >= BTN_TOOL_MOUSE) { + wacom_report_key(wcombo, BTN_LEFT, 0); + wacom_report_key(wcombo, BTN_MIDDLE, 0); + wacom_report_key(wcombo, BTN_RIGHT, 0); + wacom_report_key(wcombo, BTN_SIDE, 0); + wacom_report_key(wcombo, BTN_EXTRA, 0); + wacom_report_abs(wcombo, ABS_THROTTLE, 0); + wacom_report_abs(wcombo, ABS_RZ, 0); + } else { + wacom_report_abs(wcombo, ABS_PRESSURE, 0); + wacom_report_abs(wcombo, ABS_TILT_X, 0); + wacom_report_abs(wcombo, ABS_TILT_Y, 0); + wacom_report_key(wcombo, BTN_STYLUS, 0); + wacom_report_key(wcombo, BTN_STYLUS2, 0); + wacom_report_key(wcombo, BTN_TOUCH, 0); + wacom_report_abs(wcombo, ABS_WHEEL, 0); } + wacom_report_key(wcombo, wacom->tool[idx], 0); + wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ + wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + return 2; } return 0; } @@ -394,6 +412,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, wacom->tool[1], 1); else wacom_report_key(wcombo, wacom->tool[1], 0); + wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff); return 1; } @@ -403,6 +422,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if (result) return result-1; + /* Only large I3 and I1 & I2 support Lense Cursor */ + if((wacom->tool[idx] == BTN_TOOL_LENS) + && ((wacom->features->type == INTUOS3) + || (wacom->features->type == INTUOS3S))) + return 0; + /* Cintiq doesn't send data when RDY bit isn't set */ if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40)) return 0; @@ -554,11 +579,11 @@ static struct wacom_features wacom_features[] = { { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 63, GRAPHIRE }, { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 63, GRAPHIRE }, { "Wacom PenPartner2", 8, 3250, 2320, 255, 63, GRAPHIRE }, - { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, - { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, - { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, - { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, - { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 31, INTUOS }, + { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, + { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 31, INTUOS }, + { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 31, INTUOS }, + { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 31, INTUOS }, { "Wacom PL400", 8, 5408, 4056, 255, 0, PL }, { "Wacom PL500", 8, 6144, 4608, 255, 0, PL }, { "Wacom PL600", 8, 6126, 4604, 255, 0, PL }, @@ -571,11 +596,11 @@ static struct wacom_features wacom_features[] = { { "Wacom DTF521", 8, 6282, 4762, 511, 0, PL }, { "Wacom DTF720", 8, 6858, 5506, 511, 0, PL }, { "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU }, - { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, - { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, - { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, - { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 31, INTUOS }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, + { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 31, INTUOS }, + { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 31, INTUOS }, + { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 31, INTUOS }, { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S }, { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 }, { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 }, @@ -584,7 +609,7 @@ static struct wacom_features wacom_features[] = { { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S }, { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 31, INTUOS }, { } }; diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h index a1d9ce00797..a2302228724 100644 --- a/drivers/usb/input/wacom_wac.h +++ b/drivers/usb/input/wacom_wac.h @@ -12,6 +12,7 @@ #define STYLUS_DEVICE_ID 0x02 #define CURSOR_DEVICE_ID 0x06 #define ERASER_DEVICE_ID 0x0A +#define PAD_DEVICE_ID 0x0F enum { PENPARTNER = 0, diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 4907e8b8007..9c7eb6144d0 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -244,6 +244,20 @@ config USB_TRANCEVIBRATOR To compile this driver as a module, choose M here: the module will be called trancevibrator. +config USB_IOWARRIOR + tristate "IO Warrior driver support" + depends on USB + help + Say Y here if you want to support the IO Warrior devices from Code + Mercenaries. This includes support for the following devices: + IO Warrior 40 + IO Warrior 24 + IO Warrior 56 + IO Warrior 24 Power Vampire + + To compile this driver as a module, choose M here: the + module will be called iowarrior. + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index dac2d5b7156..b68e6b774f1 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o +obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o obj-$(CONFIG_USB_LCD) += usblcd.o obj-$(CONFIG_USB_LD) += ldusb.o obj-$(CONFIG_USB_LED) += usbled.o diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c new file mode 100644 index 00000000000..d69665c8de0 --- /dev/null +++ b/drivers/usb/misc/iowarrior.c @@ -0,0 +1,925 @@ +/* + * Native support for the I/O-Warrior USB devices + * + * Copyright (c) 2003-2005 Code Mercenaries GmbH + * written by Christian Lucht <lucht@codemercs.com> + * + * based on + + * usb-skeleton.c by Greg Kroah-Hartman <greg@kroah.com> + * brlvger.c by Stephane Dalton <sdalton@videotron.ca> + * and St�hane Doyon <s.doyon@videotron.ca> + * + * Released under the GPLv2. + */ + +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/poll.h> +#include <linux/version.h> +#include <linux/usb/iowarrior.h> + +/* Version Information */ +#define DRIVER_VERSION "v0.4.0" +#define DRIVER_AUTHOR "Christian Lucht <lucht@codemercs.com>" +#define DRIVER_DESC "USB IO-Warrior driver (Linux 2.6.x)" + +#define USB_VENDOR_ID_CODEMERCS 1984 +/* low speed iowarrior */ +#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 +#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 +#define USB_DEVICE_ID_CODEMERCS_IOWPV1 0x1511 +#define USB_DEVICE_ID_CODEMERCS_IOWPV2 0x1512 +/* full speed iowarrior */ +#define USB_DEVICE_ID_CODEMERCS_IOW56 0x1503 + +/* Get a minor range for your devices from the usb maintainer */ +#ifdef CONFIG_USB_DYNAMIC_MINORS +#define IOWARRIOR_MINOR_BASE 0 +#else +#define IOWARRIOR_MINOR_BASE 208 // SKELETON_MINOR_BASE 192 + 16, not offical yet +#endif + +/* interrupt input queue size */ +#define MAX_INTERRUPT_BUFFER 16 +/* + maximum number of urbs that are submitted for writes at the same time, + this applies to the IOWarrior56 only! + IOWarrior24 and IOWarrior40 use synchronous usb_control_msg calls. +*/ +#define MAX_WRITES_IN_FLIGHT 4 + +/* Use our own dbg macro */ +#undef dbg +#define dbg( format, arg... ) do { if( debug ) printk( KERN_DEBUG __FILE__ ": " format "\n" , ## arg ); } while ( 0 ) + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +/* Module parameters */ +static int debug = 0; +module_param(debug, bool, 0644); +MODULE_PARM_DESC(debug, "debug=1 enables debugging messages"); + +static struct usb_driver iowarrior_driver; + +/*--------------*/ +/* data */ +/*--------------*/ + +/* Structure to hold all of our device specific stuff */ +struct iowarrior { + struct mutex mutex; /* locks this structure */ + struct usb_device *udev; /* save off the usb device pointer */ + struct usb_interface *interface; /* the interface for this device */ + unsigned char minor; /* the starting minor number for this device */ + struct usb_endpoint_descriptor *int_out_endpoint; /* endpoint for reading (needed for IOW56 only) */ + struct usb_endpoint_descriptor *int_in_endpoint; /* endpoint for reading */ + struct urb *int_in_urb; /* the urb for reading data */ + unsigned char *int_in_buffer; /* buffer for data to be read */ + unsigned char serial_number; /* to detect lost packages */ + unsigned char *read_queue; /* size is MAX_INTERRUPT_BUFFER * packet size */ + wait_queue_head_t read_wait; + wait_queue_head_t write_wait; /* wait-queue for writing to the device */ + atomic_t write_busy; /* number of write-urbs submitted */ + atomic_t read_idx; + atomic_t intr_idx; + spinlock_t intr_idx_lock; /* protects intr_idx */ + atomic_t overflow_flag; /* signals an index 'rollover' */ + int present; /* this is 1 as long as the device is connected */ + int opened; /* this is 1 if the device is currently open */ + char chip_serial[9]; /* the serial number string of the chip connected */ + int report_size; /* number of bytes in a report */ + u16 product_id; +}; + +/*--------------*/ +/* globals */ +/*--------------*/ +/* prevent races between open() and disconnect() */ +static DECLARE_MUTEX(disconnect_sem); + +/* + * USB spec identifies 5 second timeouts. + */ +#define GET_TIMEOUT 5 +#define USB_REQ_GET_REPORT 0x01 +//#if 0 +static int usb_get_report(struct usb_device *dev, + struct usb_host_interface *inter, unsigned char type, + unsigned char id, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_REPORT, + USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, (type << 8) + id, + inter->desc.bInterfaceNumber, buf, size, + GET_TIMEOUT); +} +//#endif + +#define USB_REQ_SET_REPORT 0x09 + +static int usb_set_report(struct usb_interface *intf, unsigned char type, + unsigned char id, void *buf, int size) +{ + return usb_control_msg(interface_to_usbdev(intf), + usb_sndctrlpipe(interface_to_usbdev(intf), 0), + USB_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (type << 8) + id, + intf->cur_altsetting->desc.bInterfaceNumber, buf, + size, 1); +} + +/*---------------------*/ +/* driver registration */ +/*---------------------*/ +/* table of devices that work with this driver */ +static struct usb_device_id iowarrior_ids[] = { + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV2)}, + {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56)}, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, iowarrior_ids); + +/* + * USB callback handler for reading data + */ +static void iowarrior_callback(struct urb *urb) +{ + struct iowarrior *dev = (struct iowarrior *)urb->context; + int intr_idx; + int read_idx; + int aux_idx; + int offset; + int status; + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + default: + goto exit; + } + + spin_lock(&dev->intr_idx_lock); + intr_idx = atomic_read(&dev->intr_idx); + /* aux_idx become previous intr_idx */ + aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1); + read_idx = atomic_read(&dev->read_idx); + + /* queue is not empty and it's interface 0 */ + if ((intr_idx != read_idx) + && (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0)) { + /* + 1 for serial number */ + offset = aux_idx * (dev->report_size + 1); + if (!memcmp + (dev->read_queue + offset, urb->transfer_buffer, + dev->report_size)) { + /* equal values on interface 0 will be ignored */ + spin_unlock(&dev->intr_idx_lock); + goto exit; + } + } + + /* aux_idx become next intr_idx */ + aux_idx = (intr_idx == (MAX_INTERRUPT_BUFFER - 1)) ? 0 : (intr_idx + 1); + if (read_idx == aux_idx) { + /* queue full, dropping oldest input */ + read_idx = (++read_idx == MAX_INTERRUPT_BUFFER) ? 0 : read_idx; + atomic_set(&dev->read_idx, read_idx); + atomic_set(&dev->overflow_flag, 1); + } + + /* +1 for serial number */ + offset = intr_idx * (dev->report_size + 1); + memcpy(dev->read_queue + offset, urb->transfer_buffer, + dev->report_size); + *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++; + + atomic_set(&dev->intr_idx, aux_idx); + spin_unlock(&dev->intr_idx_lock); + /* tell the blocking read about the new data */ + wake_up_interruptible(&dev->read_wait); + +exit: + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status) + dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d", + __FUNCTION__, status); + +} + +/* + * USB Callback handler for write-ops + */ +static void iowarrior_write_callback(struct urb *urb) +{ + struct iowarrior *dev; + dev = (struct iowarrior *)urb->context; + /* sync/async unlink faults aren't errors */ + if (urb->status && + !(urb->status == -ENOENT || + urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) { + dbg("%s - nonzero write bulk status received: %d", + __func__, urb->status); + } + /* free up our allocated buffer */ + usb_buffer_free(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); + /* tell a waiting writer the interrupt-out-pipe is available again */ + atomic_dec(&dev->write_busy); + wake_up_interruptible(&dev->write_wait); +} + +/** + * iowarrior_delete + */ +static inline void iowarrior_delete(struct iowarrior *dev) +{ + dbg("%s - minor %d", __func__, dev->minor); + kfree(dev->int_in_buffer); + usb_free_urb(dev->int_in_urb); + kfree(dev->read_queue); + kfree(dev); +} + +/*---------------------*/ +/* fops implementation */ +/*---------------------*/ + +static int read_index(struct iowarrior *dev) +{ + int intr_idx, read_idx; + + read_idx = atomic_read(&dev->read_idx); + intr_idx = atomic_read(&dev->intr_idx); + + return (read_idx == intr_idx ? -1 : read_idx); +} + +/** + * iowarrior_read + */ +static ssize_t iowarrior_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct iowarrior *dev; + int read_idx; + int offset; + + dev = (struct iowarrior *)file->private_data; + + /* verify that the device wasn't unplugged */ + if (dev == NULL || !dev->present) + return -ENODEV; + + dbg("%s - minor %d, count = %zd", __func__, dev->minor, count); + + /* read count must be packet size (+ time stamp) */ + if ((count != dev->report_size) + && (count != (dev->report_size + 1))) + return -EINVAL; + + /* repeat until no buffer overrun in callback handler occur */ + do { + atomic_set(&dev->overflow_flag, 0); + if ((read_idx = read_index(dev)) == -1) { + /* queue emty */ + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + else { + //next line will return when there is either new data, or the device is unplugged + int r = wait_event_interruptible(dev->read_wait, + (!dev->present + || (read_idx = + read_index + (dev)) != + -1)); + if (r) { + //we were interrupted by a signal + return -ERESTART; + } + if (!dev->present) { + //The device was unplugged + return -ENODEV; + } + if (read_idx == -1) { + // Can this happen ??? + return 0; + } + } + } + + offset = read_idx * (dev->report_size + 1); + if (copy_to_user(buffer, dev->read_queue + offset, count)) { + return -EFAULT; + } + } while (atomic_read(&dev->overflow_flag)); + + read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx; + atomic_set(&dev->read_idx, read_idx); + return count; +} + +/* + * iowarrior_write + */ +static ssize_t iowarrior_write(struct file *file, + const char __user *user_buffer, + size_t count, loff_t *ppos) +{ + struct iowarrior *dev; + int retval = 0; + char *buf = NULL; /* for IOW24 and IOW56 we need a buffer */ + struct urb *int_out_urb = NULL; + + dev = (struct iowarrior *)file->private_data; + + mutex_lock(&dev->mutex); + /* verify that the device wasn't unplugged */ + if (dev == NULL || !dev->present) { + retval = -ENODEV; + goto exit; + } + dbg("%s - minor %d, count = %zd", __func__, dev->minor, count); + /* if count is 0 we're already done */ + if (count == 0) { + retval = 0; + goto exit; + } + /* We only accept full reports */ + if (count != dev->report_size) { + retval = -EINVAL; + goto exit; + } + switch (dev->product_id) { + case USB_DEVICE_ID_CODEMERCS_IOW24: + case USB_DEVICE_ID_CODEMERCS_IOWPV1: + case USB_DEVICE_ID_CODEMERCS_IOWPV2: + case USB_DEVICE_ID_CODEMERCS_IOW40: + /* IOW24 and IOW40 use a synchronous call */ + buf = kmalloc(8, GFP_KERNEL); /* 8 bytes are enough for both products */ + if (!buf) { + retval = -ENOMEM; + goto exit; + } + if (copy_from_user(buf, user_buffer, count)) { + retval = -EFAULT; + kfree(buf); + goto exit; + } + retval = usb_set_report(dev->interface, 2, 0, buf, count); + kfree(buf); + goto exit; + break; + case USB_DEVICE_ID_CODEMERCS_IOW56: + /* The IOW56 uses asynchronous IO and more urbs */ + if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) { + /* Wait until we are below the limit for submitted urbs */ + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto exit; + } else { + retval = wait_event_interruptible(dev->write_wait, + (!dev->present || (atomic_read (&dev-> write_busy) < MAX_WRITES_IN_FLIGHT))); + if (retval) { + /* we were interrupted by a signal */ + retval = -ERESTART; + goto exit; + } + if (!dev->present) { + /* The device was unplugged */ + retval = -ENODEV; + goto exit; + } + if (!dev->opened) { + /* We were closed while waiting for an URB */ + retval = -ENODEV; + goto exit; + } + } + } + atomic_inc(&dev->write_busy); + int_out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!int_out_urb) { + retval = -ENOMEM; + dbg("%s Unable to allocate urb ", __func__); + goto error; + } + buf = usb_buffer_alloc(dev->udev, dev->report_size, + GFP_KERNEL, &int_out_urb->transfer_dma); + if (!buf) { + retval = -ENOMEM; + dbg("%s Unable to allocate buffer ", __func__); + goto error; + } + usb_fill_int_urb(int_out_urb, dev->udev, + usb_sndintpipe(dev->udev, + dev->int_out_endpoint->bEndpointAddress), + buf, dev->report_size, + iowarrior_write_callback, dev, + dev->int_out_endpoint->bInterval); + int_out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + if (copy_from_user(buf, user_buffer, count)) { + retval = -EFAULT; + goto error; + } + retval = usb_submit_urb(int_out_urb, GFP_KERNEL); + if (retval) { + dbg("%s submit error %d for urb nr.%d", __func__, + retval, atomic_read(&dev->write_busy)); + goto error; + } + /* submit was ok */ + retval = count; + usb_free_urb(int_out_urb); + goto exit; + break; + default: + /* what do we have here ? An unsupported Product-ID ? */ + dev_err(&dev->interface->dev, "%s - not supported for product=0x%x", + __FUNCTION__, dev->product_id); + retval = -EFAULT; + goto exit; + break; + } +error: + usb_buffer_free(dev->udev, dev->report_size, buf, + int_out_urb->transfer_dma); + usb_free_urb(int_out_urb); + atomic_dec(&dev->write_busy); + wake_up_interruptible(&dev->write_wait); +exit: + mutex_unlock(&dev->mutex); + return retval; +} + +/** + * iowarrior_ioctl + */ +static int iowarrior_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct iowarrior *dev = NULL; + __u8 *buffer; + __u8 __user *user_buffer; + int retval; + int io_res; /* checks for bytes read/written and copy_to/from_user results */ + + dev = (struct iowarrior *)file->private_data; + if (dev == NULL) { + return -ENODEV; + } + + buffer = kzalloc(dev->report_size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + /* lock this object */ + mutex_lock(&dev->mutex); + + /* verify that the device wasn't unplugged */ + if (!dev->present) { + mutex_unlock(&dev->mutex); + return -ENODEV; + } + + dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd, + arg); + + retval = 0; + io_res = 0; + switch (cmd) { + case IOW_WRITE: + if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || + dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || + dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || + dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { + user_buffer = (__u8 __user *)arg; + io_res = copy_from_user(buffer, user_buffer, + dev->report_size); + if (io_res) { + retval = -EFAULT; + } else { + io_res = usb_set_report(dev->interface, 2, 0, + buffer, + dev->report_size); + if (io_res < 0) + retval = io_res; + } + } else { + retval = -EINVAL; + dev_err(&dev->interface->dev, + "ioctl 'IOW_WRITE' is not supported for product=0x%x.", + dev->product_id); + } + break; + case IOW_READ: + user_buffer = (__u8 __user *)arg; + io_res = usb_get_report(dev->udev, + dev->interface->cur_altsetting, 1, 0, + buffer, dev->report_size); + if (io_res < 0) + retval = io_res; + else { + io_res = copy_to_user(user_buffer, buffer, dev->report_size); + if (io_res < 0) + retval = -EFAULT; + } + break; + case IOW_GETINFO: + { + /* Report available information for the device */ + struct iowarrior_info info; + /* needed for power consumption */ + struct usb_config_descriptor *cfg_descriptor = &dev->udev->actconfig->desc; + + /* directly from the descriptor */ + info.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + info.product = dev->product_id; + info.revision = le16_to_cpu(dev->udev->descriptor.bcdDevice); + + /* 0==UNKNOWN, 1==LOW(usb1.1) ,2=FULL(usb1.1), 3=HIGH(usb2.0) */ + info.speed = le16_to_cpu(dev->udev->speed); + info.if_num = dev->interface->cur_altsetting->desc.bInterfaceNumber; + info.report_size = dev->report_size; + + /* serial number string has been read earlier 8 chars or empty string */ + memcpy(info.serial, dev->chip_serial, + sizeof(dev->chip_serial)); + if (cfg_descriptor == NULL) { + info.power = -1; /* no information available */ + } else { + /* the MaxPower is stored in units of 2mA to make it fit into a byte-value */ + info.power = cfg_descriptor->bMaxPower * 2; + } + io_res = copy_to_user((struct iowarrior_info __user *)arg, &info, + sizeof(struct iowarrior_info)); + if (io_res < 0) + retval = -EFAULT; + break; + } + default: + /* return that we did not understand this ioctl call */ + retval = -ENOTTY; + break; + } + + /* unlock the device */ + mutex_unlock(&dev->mutex); + return retval; +} + +/** + * iowarrior_open + */ +static int iowarrior_open(struct inode *inode, struct file *file) +{ + struct iowarrior *dev = NULL; + struct usb_interface *interface; + int subminor; + int retval = 0; + + dbg("%s", __func__); + + subminor = iminor(inode); + + /* prevent disconnects */ + down(&disconnect_sem); + + interface = usb_find_interface(&iowarrior_driver, subminor); + if (!interface) { + err("%s - error, can't find device for minor %d", __FUNCTION__, + subminor); + retval = -ENODEV; + goto out; + } + + dev = usb_get_intfdata(interface); + if (!dev) { + retval = -ENODEV; + goto out; + } + + /* Only one process can open each device, no sharing. */ + if (dev->opened) { + retval = -EBUSY; + goto out; + } + + /* setup interrupt handler for receiving values */ + if ((retval = usb_submit_urb(dev->int_in_urb, GFP_KERNEL)) < 0) { + dev_err(&interface->dev, "Error %d while submitting URB\n", retval); + retval = -EFAULT; + goto out; + } + /* increment our usage count for the driver */ + ++dev->opened; + /* save our object in the file's private structure */ + file->private_data = dev; + retval = 0; + +out: + up(&disconnect_sem); + return retval; +} + +/** + * iowarrior_release + */ +static int iowarrior_release(struct inode *inode, struct file *file) +{ + struct iowarrior *dev; + int retval = 0; + + dev = (struct iowarrior *)file->private_data; + if (dev == NULL) { + return -ENODEV; + } + + dbg("%s - minor %d", __func__, dev->minor); + + /* lock our device */ + mutex_lock(&dev->mutex); + + if (dev->opened <= 0) { + retval = -ENODEV; /* close called more than once */ + mutex_unlock(&dev->mutex); + } else { + dev->opened = 0; /* we're closeing now */ + retval = 0; + if (dev->present) { + /* + The device is still connected so we only shutdown + pending read-/write-ops. + */ + usb_kill_urb(dev->int_in_urb); + wake_up_interruptible(&dev->read_wait); + wake_up_interruptible(&dev->write_wait); + mutex_unlock(&dev->mutex); + } else { + /* The device was unplugged, cleanup resources */ + mutex_unlock(&dev->mutex); + iowarrior_delete(dev); + } + } + return retval; +} + +static unsigned iowarrior_poll(struct file *file, poll_table * wait) +{ + struct iowarrior *dev = file->private_data; + unsigned int mask = 0; + + if (!dev->present) + return POLLERR | POLLHUP; + + poll_wait(file, &dev->read_wait, wait); + poll_wait(file, &dev->write_wait, wait); + + if (!dev->present) + return POLLERR | POLLHUP; + + if (read_index(dev) != -1) + mask |= POLLIN | POLLRDNORM; + + if (atomic_read(&dev->write_busy) < MAX_WRITES_IN_FLIGHT) + mask |= POLLOUT | POLLWRNORM; + return mask; +} + +/* + * File operations needed when we register this driver. + * This assumes that this driver NEEDS file operations, + * of course, which means that the driver is expected + * to have a node in the /dev directory. If the USB + * device were for a network interface then the driver + * would use "struct net_driver" instead, and a serial + * device would use "struct tty_driver". + */ +static struct file_operations iowarrior_fops = { + .owner = THIS_MODULE, + .write = iowarrior_write, + .read = iowarrior_read, + .ioctl = iowarrior_ioctl, + .open = iowarrior_open, + .release = iowarrior_release, + .poll = iowarrior_poll, +}; + +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with devfs and the driver core + */ +static struct usb_class_driver iowarrior_class = { + .name = "iowarrior%d", + .fops = &iowarrior_fops, + .minor_base = IOWARRIOR_MINOR_BASE, +}; + +/*---------------------------------*/ +/* probe and disconnect functions */ +/*---------------------------------*/ +/** + * iowarrior_probe + * + * Called by the usb core when a new device is connected that it thinks + * this driver might be interested in. + */ +static int iowarrior_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct iowarrior *dev = NULL; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int i; + int retval = -ENOMEM; + int idele = 0; + + /* allocate memory for our device state and intialize it */ + dev = kzalloc(sizeof(struct iowarrior), GFP_KERNEL); + if (dev == NULL) { + dev_err(&interface->dev, "Out of memory"); + return retval; + } + + mutex_init(&dev->mutex); + + atomic_set(&dev->intr_idx, 0); + atomic_set(&dev->read_idx, 0); + spin_lock_init(&dev->intr_idx_lock); + atomic_set(&dev->overflow_flag, 0); + init_waitqueue_head(&dev->read_wait); + atomic_set(&dev->write_busy, 0); + init_waitqueue_head(&dev->write_wait); + + dev->udev = udev; + dev->interface = interface; + + iface_desc = interface->cur_altsetting; + dev->product_id = le16_to_cpu(udev->descriptor.idProduct); + + /* set up the endpoint information */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (usb_endpoint_is_int_in(endpoint)) + dev->int_in_endpoint = endpoint; + if (usb_endpoint_is_int_out(endpoint)) + /* this one will match for the IOWarrior56 only */ + dev->int_out_endpoint = endpoint; + } + /* we have to check the report_size often, so remember it in the endianess suitable for our machine */ + dev->report_size = le16_to_cpu(dev->int_in_endpoint->wMaxPacketSize); + if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) && + (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56)) + /* IOWarrior56 has wMaxPacketSize different from report size */ + dev->report_size = 7; + + /* create the urb and buffer for reading */ + dev->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->int_in_urb) { + dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); + goto error; + } + dev->int_in_buffer = kmalloc(dev->report_size, GFP_KERNEL); + if (!dev->int_in_buffer) { + dev_err(&interface->dev, "Couldn't allocate int_in_buffer\n"); + goto error; + } + usb_fill_int_urb(dev->int_in_urb, dev->udev, + usb_rcvintpipe(dev->udev, + dev->int_in_endpoint->bEndpointAddress), + dev->int_in_buffer, dev->report_size, + iowarrior_callback, dev, + dev->int_in_endpoint->bInterval); + /* create an internal buffer for interrupt data from the device */ + dev->read_queue = + kmalloc(((dev->report_size + 1) * MAX_INTERRUPT_BUFFER), + GFP_KERNEL); + if (!dev->read_queue) { + dev_err(&interface->dev, "Couldn't allocate read_queue\n"); + goto error; + } + /* Get the serial-number of the chip */ + memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); + usb_string(udev, udev->descriptor.iSerialNumber, dev->chip_serial, + sizeof(dev->chip_serial)); + if (strlen(dev->chip_serial) != 8) + memset(dev->chip_serial, 0x00, sizeof(dev->chip_serial)); + + /* Set the idle timeout to 0, if this is interface 0 */ + if (dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) { + idele = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x0A, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, + 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + dbg("idele = %d", idele); + } + /* allow device read and ioctl */ + dev->present = 1; + + /* we can register the device now, as it is ready */ + usb_set_intfdata(interface, dev); + + retval = usb_register_dev(interface, &iowarrior_class); + if (retval) { + /* something prevented us from registering this driver */ + dev_err(&interface->dev, "Not able to get a minor for this device.\n"); + usb_set_intfdata(interface, NULL); + goto error; + } + + dev->minor = interface->minor; + + /* let the user know what node this device is now attached to */ + dev_info(&interface->dev, "IOWarrior product=0x%x, serial=%s interface=%d " + "now attached to iowarrior%d\n", dev->product_id, dev->chip_serial, + iface_desc->desc.bInterfaceNumber, dev->minor - IOWARRIOR_MINOR_BASE); + return retval; + +error: + iowarrior_delete(dev); + return retval; +} + +/** + * iowarrior_disconnect + * + * Called by the usb core when the device is removed from the system. + */ +static void iowarrior_disconnect(struct usb_interface *interface) +{ + struct iowarrior *dev; + int minor; + + /* prevent races with open() */ + down(&disconnect_sem); + + dev = usb_get_intfdata(interface); + usb_set_intfdata(interface, NULL); + + mutex_lock(&dev->mutex); + + minor = dev->minor; + + /* give back our minor */ + usb_deregister_dev(interface, &iowarrior_class); + + /* prevent device read, write and ioctl */ + dev->present = 0; + + mutex_unlock(&dev->mutex); + + if (dev->opened) { + /* There is a process that holds a filedescriptor to the device , + so we only shutdown read-/write-ops going on. + Deleting the device is postponed until close() was called. + */ + usb_kill_urb(dev->int_in_urb); + wake_up_interruptible(&dev->read_wait); + wake_up_interruptible(&dev->write_wait); + } else { + /* no process is using the device, cleanup now */ + iowarrior_delete(dev); + } + up(&disconnect_sem); + + dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n", + minor - IOWARRIOR_MINOR_BASE); +} + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver iowarrior_driver = { + .name = "iowarrior", + .probe = iowarrior_probe, + .disconnect = iowarrior_disconnect, + .id_table = iowarrior_ids, +}; + +static int __init iowarrior_init(void) +{ + return usb_register(&iowarrior_driver); +} + +static void __exit iowarrior_exit(void) +{ + usb_deregister(&iowarrior_driver); +} + +module_init(iowarrior_init); +module_exit(iowarrior_exit); diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index c01dfe60367..b2bedd974ac 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1165,7 +1165,7 @@ err_dev: return rc; } -void __exit mon_bin_exit(void) +void mon_bin_exit(void) { cdev_del(&mon_bin_cdev); unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR); diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index d38a1279d9d..494ee3b9a22 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -520,7 +520,7 @@ int __init mon_text_init(void) return 0; } -void __exit mon_text_exit(void) +void mon_text_exit(void) { debugfs_remove(mon_dir); } diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h index 4f949ce8a7f..efdfd8993d9 100644 --- a/drivers/usb/mon/usb_mon.h +++ b/drivers/usb/mon/usb_mon.h @@ -57,9 +57,9 @@ void mon_text_del(struct mon_bus *mbus); // void mon_bin_add(struct mon_bus *); int __init mon_text_init(void); -void __exit mon_text_exit(void); +void mon_text_exit(void); int __init mon_bin_init(void); -void __exit mon_bin_exit(void); +void mon_bin_exit(void); /* * DMA interface. diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 0f3d7dbb537..3de564b2314 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -186,6 +186,15 @@ config USB_NET_CDCETHER IEEE 802 "local assignment" bit is set in the address, a "usbX" name is used instead. +config USB_NET_DM9601 + tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices" + depends on USB_USBNET + select CRC32 + select USB_USBNET_MII + help + This option adds support for Davicom DM9601 based USB 1.1 + 10/100 Ethernet adapters. + config USB_NET_GL620A tristate "GeneSys GL620USB-A based cables" depends on USB_USBNET diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 7b51964de17..595a539f838 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o obj-$(CONFIG_USB_RTL8150) += rtl8150.o obj-$(CONFIG_USB_NET_AX8817X) += asix.o obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o +obj-$(CONFIG_USB_NET_DM9601) += dm9601.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o obj-$(CONFIG_USB_NET_NET1080) += net1080.o obj-$(CONFIG_USB_NET_PLUSB) += plusb.o diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 7ef2e4b5e39..5808ea08245 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -1395,9 +1395,9 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x07b8, 0x420a), .driver_info = (unsigned long) &hawking_uf200_info, }, { - // Billionton Systems, USB2AR - USB_DEVICE (0x08dd, 0x90ff), - .driver_info = (unsigned long) &ax8817x_info, + // Billionton Systems, USB2AR + USB_DEVICE (0x08dd, 0x90ff), + .driver_info = (unsigned long) &ax8817x_info, }, { // ATEN UC210T USB_DEVICE (0x0557, 0x2009), @@ -1423,9 +1423,13 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x1631, 0x6200), .driver_info = (unsigned long) &ax8817x_info, }, { + // JVC MP-PRX1 Port Replicator + USB_DEVICE (0x04f1, 0x3008), + .driver_info = (unsigned long) &ax8817x_info, +}, { // ASIX AX88772 10/100 - USB_DEVICE (0x0b95, 0x7720), - .driver_info = (unsigned long) &ax88772_info, + USB_DEVICE (0x0b95, 0x7720), + .driver_info = (unsigned long) &ax88772_info, }, { // ASIX AX88178 10/100/1000 USB_DEVICE (0x0b95, 0x1780), diff --git a/drivers/usb/net/dm9601.c b/drivers/usb/net/dm9601.c new file mode 100644 index 00000000000..4a932e1cd93 --- /dev/null +++ b/drivers/usb/net/dm9601.c @@ -0,0 +1,606 @@ +/* + * Davicom DM9601 USB 1.1 10/100Mbps ethernet devices + * + * Peter Korsgaard <jacmet@sunsite.dk> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +//#define DEBUG + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/usb.h> +#include <linux/crc32.h> + +#include "usbnet.h" + +/* datasheet: + http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf +*/ + +/* control requests */ +#define DM_READ_REGS 0x00 +#define DM_WRITE_REGS 0x01 +#define DM_READ_MEMS 0x02 +#define DM_WRITE_REG 0x03 +#define DM_WRITE_MEMS 0x05 +#define DM_WRITE_MEM 0x07 + +/* registers */ +#define DM_NET_CTRL 0x00 +#define DM_RX_CTRL 0x05 +#define DM_SHARED_CTRL 0x0b +#define DM_SHARED_ADDR 0x0c +#define DM_SHARED_DATA 0x0d /* low + high */ +#define DM_PHY_ADDR 0x10 /* 6 bytes */ +#define DM_MCAST_ADDR 0x16 /* 8 bytes */ +#define DM_GPR_CTRL 0x1e +#define DM_GPR_DATA 0x1f + +#define DM_MAX_MCAST 64 +#define DM_MCAST_SIZE 8 +#define DM_EEPROM_LEN 256 +#define DM_TX_OVERHEAD 2 /* 2 byte header */ +#define DM_RX_OVERHEAD 7 /* 3 byte header + 4 byte crc tail */ +#define DM_TIMEOUT 1000 + + +static int dm_read(struct usbnet *dev, u8 reg, u16 length, void *data) +{ + devdbg(dev, "dm_read() reg=0x%02x length=%d", reg, length); + return usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + DM_READ_REGS, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, reg, data, length, USB_CTRL_SET_TIMEOUT); +} + +static int dm_read_reg(struct usbnet *dev, u8 reg, u8 *value) +{ + return dm_read(dev, reg, 1, value); +} + +static int dm_write(struct usbnet *dev, u8 reg, u16 length, void *data) +{ + devdbg(dev, "dm_write() reg=0x%02x, length=%d", reg, length); + return usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + DM_WRITE_REGS, + USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, + 0, reg, data, length, USB_CTRL_SET_TIMEOUT); +} + +static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) +{ + devdbg(dev, "dm_write_reg() reg=0x%02x, value=0x%02x", reg, value); + return usb_control_msg(dev->udev, + usb_sndctrlpipe(dev->udev, 0), + DM_WRITE_REG, + USB_DIR_OUT | USB_TYPE_VENDOR |USB_RECIP_DEVICE, + value, reg, 0, 0, USB_CTRL_SET_TIMEOUT); +} + +static void dm_write_async_callback(struct urb *urb) +{ + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + + if (urb->status < 0) + printk(KERN_DEBUG "dm_write_async_callback() failed with %d", + urb->status); + + kfree(req); + usb_free_urb(urb); +} + +static void dm_write_async(struct usbnet *dev, u8 reg, u16 length, void *data) +{ + struct usb_ctrlrequest *req; + struct urb *urb; + int status; + + devdbg(dev, "dm_write_async() reg=0x%02x length=%d", reg, length); + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + deverr(dev, "Error allocating URB in dm_write_async!"); + return; + } + + req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); + if (!req) { + deverr(dev, "Failed to allocate memory for control request"); + usb_free_urb(urb); + return; + } + + req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + req->bRequest = DM_WRITE_REGS; + req->wValue = 0; + req->wIndex = cpu_to_le16(reg); + req->wLength = cpu_to_le16(length); + + usb_fill_control_urb(urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), + (void *)req, data, length, + dm_write_async_callback, req); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { + deverr(dev, "Error submitting the control message: status=%d", + status); + kfree(req); + usb_free_urb(urb); + } +} + +static void dm_write_reg_async(struct usbnet *dev, u8 reg, u8 value) +{ + struct usb_ctrlrequest *req; + struct urb *urb; + int status; + + devdbg(dev, "dm_write_reg_async() reg=0x%02x value=0x%02x", + reg, value); + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + deverr(dev, "Error allocating URB in dm_write_async!"); + return; + } + + req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); + if (!req) { + deverr(dev, "Failed to allocate memory for control request"); + usb_free_urb(urb); + return; + } + + req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; + req->bRequest = DM_WRITE_REG; + req->wValue = cpu_to_le16(value); + req->wIndex = cpu_to_le16(reg); + req->wLength = 0; + + usb_fill_control_urb(urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), + (void *)req, 0, 0, dm_write_async_callback, req); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status < 0) { + deverr(dev, "Error submitting the control message: status=%d", + status); + kfree(req); + usb_free_urb(urb); + } +} + +static int dm_read_shared_word(struct usbnet *dev, int phy, u8 reg, u16 *value) +{ + int ret, i; + + mutex_lock(&dev->phy_mutex); + + dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); + dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0xc : 0x4); + + for (i = 0; i < DM_TIMEOUT; i++) { + u8 tmp; + + udelay(1); + ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp); + if (ret < 0) + goto out; + + /* ready */ + if ((tmp & 1) == 0) + break; + } + + if (i == DM_TIMEOUT) { + deverr(dev, "%s read timed out!", phy ? "phy" : "eeprom"); + ret = -EIO; + goto out; + } + + dm_write_reg(dev, DM_SHARED_CTRL, 0x0); + ret = dm_read(dev, DM_SHARED_DATA, 2, value); + + devdbg(dev, "read shared %d 0x%02x returned 0x%04x, %d", + phy, reg, *value, ret); + + out: + mutex_unlock(&dev->phy_mutex); + return ret; +} + +static int dm_write_shared_word(struct usbnet *dev, int phy, u8 reg, u16 value) +{ + int ret, i; + + mutex_lock(&dev->phy_mutex); + + ret = dm_write(dev, DM_SHARED_DATA, 2, &value); + if (ret < 0) + goto out; + + dm_write_reg(dev, DM_SHARED_ADDR, phy ? (reg | 0x40) : reg); + dm_write_reg(dev, DM_SHARED_CTRL, phy ? 0x1c : 0x14); + + for (i = 0; i < DM_TIMEOUT; i++) { + u8 tmp; + + udelay(1); + ret = dm_read_reg(dev, DM_SHARED_CTRL, &tmp); + if (ret < 0) + goto out; + + /* ready */ + if ((tmp & 1) == 0) + break; + } + + if (i == DM_TIMEOUT) { + deverr(dev, "%s write timed out!", phy ? "phy" : "eeprom"); + ret = -EIO; + goto out; + } + + dm_write_reg(dev, DM_SHARED_CTRL, 0x0); + +out: + mutex_unlock(&dev->phy_mutex); + return ret; +} + +static int dm_read_eeprom_word(struct usbnet *dev, u8 offset, void *value) +{ + return dm_read_shared_word(dev, 0, offset, value); +} + + + +static int dm9601_get_eeprom_len(struct net_device *dev) +{ + return DM_EEPROM_LEN; +} + +static int dm9601_get_eeprom(struct net_device *net, + struct ethtool_eeprom *eeprom, u8 * data) +{ + struct usbnet *dev = netdev_priv(net); + u16 *ebuf = (u16 *) data; + int i; + + /* access is 16bit */ + if ((eeprom->offset % 2) || (eeprom->len % 2)) + return -EINVAL; + + for (i = 0; i < eeprom->len / 2; i++) { + if (dm_read_eeprom_word(dev, eeprom->offset / 2 + i, + &ebuf[i]) < 0) + return -EINVAL; + } + return 0; +} + +static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc) +{ + struct usbnet *dev = netdev_priv(netdev); + + u16 res; + + if (phy_id) { + devdbg(dev, "Only internal phy supported"); + return 0; + } + + dm_read_shared_word(dev, 1, loc, &res); + + devdbg(dev, + "dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", + phy_id, loc, le16_to_cpu(res)); + + return le16_to_cpu(res); +} + +static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc, + int val) +{ + struct usbnet *dev = netdev_priv(netdev); + u16 res = cpu_to_le16(val); + + if (phy_id) { + devdbg(dev, "Only internal phy supported"); + return; + } + + devdbg(dev,"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", + phy_id, loc, val); + + dm_write_shared_word(dev, 1, loc, res); +} + +static void dm9601_get_drvinfo(struct net_device *net, + struct ethtool_drvinfo *info) +{ + /* Inherit standard device info */ + usbnet_get_drvinfo(net, info); + info->eedump_len = DM_EEPROM_LEN; +} + +static u32 dm9601_get_link(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + return mii_link_ok(&dev->mii); +} + +static int dm9601_ioctl(struct net_device *net, struct ifreq *rq, int cmd) +{ + struct usbnet *dev = netdev_priv(net); + + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +static struct ethtool_ops dm9601_ethtool_ops = { + .get_drvinfo = dm9601_get_drvinfo, + .get_link = dm9601_get_link, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_eeprom_len = dm9601_get_eeprom_len, + .get_eeprom = dm9601_get_eeprom, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, +}; + +static void dm9601_set_multicast(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + /* We use the 20 byte dev->data for our 8 byte filter buffer + * to avoid allocating memory that is tricky to free later */ + u8 *hashes = (u8 *) & dev->data; + u8 rx_ctl = 0x01; + + memset(hashes, 0x00, DM_MCAST_SIZE); + hashes[DM_MCAST_SIZE - 1] |= 0x80; /* broadcast address */ + + if (net->flags & IFF_PROMISC) { + rx_ctl |= 0x02; + } else if (net->flags & IFF_ALLMULTI || net->mc_count > DM_MAX_MCAST) { + rx_ctl |= 0x04; + } else if (net->mc_count) { + struct dev_mc_list *mc_list = net->mc_list; + int i; + + for (i = 0; i < net->mc_count; i++) { + u32 crc = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; + hashes[crc >> 3] |= 1 << (crc & 0x7); + } + } + + dm_write_async(dev, DM_MCAST_ADDR, DM_MCAST_SIZE, hashes); + dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl); +} + +static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int ret; + + ret = usbnet_get_endpoints(dev, intf); + if (ret) + goto out; + + dev->net->do_ioctl = dm9601_ioctl; + dev->net->set_multicast_list = dm9601_set_multicast; + dev->net->ethtool_ops = &dm9601_ethtool_ops; + dev->net->hard_header_len += DM_TX_OVERHEAD; + dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; + dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD; + + dev->mii.dev = dev->net; + dev->mii.mdio_read = dm9601_mdio_read; + dev->mii.mdio_write = dm9601_mdio_write; + dev->mii.phy_id_mask = 0x1f; + dev->mii.reg_num_mask = 0x1f; + + /* reset */ + ret = dm_write_reg(dev, DM_NET_CTRL, 1); + udelay(20); + + /* read MAC */ + ret = dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr); + if (ret < 0) { + printk(KERN_ERR "Error reading MAC address\n"); + ret = -ENODEV; + goto out; + } + + + /* power up phy */ + dm_write_reg(dev, DM_GPR_CTRL, 1); + dm_write_reg(dev, DM_GPR_DATA, 0); + + /* receive broadcast packets */ + dm9601_set_multicast(dev->net); + + dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + dm9601_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); + mii_nway_restart(&dev->mii); + +out: + return ret; +} + +static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + u8 status; + int len; + + /* format: + b0: rx status + b1: packet length (incl crc) low + b2: packet length (incl crc) high + b3..n-4: packet data + bn-3..bn: ethernet crc + */ + + if (unlikely(skb->len < DM_RX_OVERHEAD)) { + dev_err(&dev->udev->dev, "unexpected tiny rx frame\n"); + return 0; + } + + status = skb->data[0]; + len = (skb->data[1] | (skb->data[2] << 8)) - 4; + + if (unlikely(status & 0xbf)) { + if (status & 0x01) dev->stats.rx_fifo_errors++; + if (status & 0x02) dev->stats.rx_crc_errors++; + if (status & 0x04) dev->stats.rx_frame_errors++; + if (status & 0x20) dev->stats.rx_missed_errors++; + if (status & 0x90) dev->stats.rx_length_errors++; + return 0; + } + + skb_pull(skb, 3); + skb_trim(skb, len); + + return 1; +} + +static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, + gfp_t flags) +{ + int len; + + /* format: + b0: packet length low + b1: packet length high + b3..n: packet data + */ + + if (skb_headroom(skb) < DM_TX_OVERHEAD) { + struct sk_buff *skb2; + + skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + __skb_push(skb, DM_TX_OVERHEAD); + + len = skb->len; + /* usbnet adds padding if length is a multiple of packet size + if so, adjust length value in header */ + if ((len % dev->maxpacket) == 0) + len++; + + skb->data[0] = len; + skb->data[1] = len >> 8; + + return skb; +} + +static void dm9601_status(struct usbnet *dev, struct urb *urb) +{ + int link; + u8 *buf; + + /* format: + b0: net status + b1: tx status 1 + b2: tx status 2 + b3: rx status + b4: rx overflow + b5: rx count + b6: tx count + b7: gpr + */ + + if (urb->actual_length < 8) + return; + + buf = urb->transfer_buffer; + + link = !!(buf[0] & 0x40); + if (netif_carrier_ok(dev->net) != link) { + if (link) { + netif_carrier_on(dev->net); + usbnet_defer_kevent (dev, EVENT_LINK_RESET); + } + else + netif_carrier_off(dev->net); + devdbg(dev, "Link Status is: %d", link); + } +} + +static int dm9601_link_reset(struct usbnet *dev) +{ + struct ethtool_cmd ecmd; + + mii_check_media(&dev->mii, 1, 1); + mii_ethtool_gset(&dev->mii, &ecmd); + + devdbg(dev, "link_reset() speed: %d duplex: %d", + ecmd.speed, ecmd.duplex); + + return 0; +} + +static const struct driver_info dm9601_info = { + .description = "Davicom DM9601 USB Ethernet", + .flags = FLAG_ETHER, + .bind = dm9601_bind, + .rx_fixup = dm9601_rx_fixup, + .tx_fixup = dm9601_tx_fixup, + .status = dm9601_status, + .link_reset = dm9601_link_reset, + .reset = dm9601_link_reset, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE(0x0a46, 0x9601), /* Davicom USB-100 */ + .driver_info = (unsigned long)&dm9601_info, + }, + {}, // END +}; + +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver dm9601_driver = { + .name = "dm9601", + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init dm9601_init(void) +{ + return usb_register(&dm9601_driver); +} + +static void __exit dm9601_exit(void) +{ + usb_deregister(&dm9601_driver); +} + +module_init(dm9601_init); +module_exit(dm9601_exit); + +MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); +MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 4695952b647..c525b42dadd 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -513,6 +513,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) }, { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, + { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 7eff1c03ba8..1bdda935f7d 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -491,6 +491,12 @@ #define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */ #define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */ +/* + * Telldus Technologies + */ +#define TELLDUS_VID 0x1781 /* Vendor ID */ +#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 9963a8b7584..db92a7fb1f7 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -67,50 +67,95 @@ static int option_tiocmset(struct usb_serial_port *port, struct file *file, static int option_send_setup(struct usb_serial_port *port); /* Vendor and product IDs */ -#define OPTION_VENDOR_ID 0x0AF0 -#define HUAWEI_VENDOR_ID 0x12D1 -#define NOVATELWIRELESS_VENDOR_ID 0x1410 -#define ANYDATA_VENDOR_ID 0x16d5 - -#define OPTION_PRODUCT_OLD 0x5000 -#define OPTION_PRODUCT_FUSION 0x6000 -#define OPTION_PRODUCT_FUSION2 0x6300 -#define OPTION_PRODUCT_COBRA 0x6500 -#define OPTION_PRODUCT_COBRA2 0x6600 -#define OPTION_PRODUCT_GTMAX36 0x6701 -#define HUAWEI_PRODUCT_E600 0x1001 -#define HUAWEI_PRODUCT_E220 0x1003 -#define NOVATELWIRELESS_PRODUCT_U740 0x1400 -#define ANYDATA_PRODUCT_ID 0x6501 +#define OPTION_VENDOR_ID 0x0AF0 +#define OPTION_PRODUCT_COLT 0x5000 +#define OPTION_PRODUCT_RICOLA 0x6000 +#define OPTION_PRODUCT_RICOLA_LIGHT 0x6100 +#define OPTION_PRODUCT_RICOLA_QUAD 0x6200 +#define OPTION_PRODUCT_RICOLA_QUAD_LIGHT 0x6300 +#define OPTION_PRODUCT_RICOLA_NDIS 0x6050 +#define OPTION_PRODUCT_RICOLA_NDIS_LIGHT 0x6150 +#define OPTION_PRODUCT_RICOLA_NDIS_QUAD 0x6250 +#define OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT 0x6350 +#define OPTION_PRODUCT_COBRA 0x6500 +#define OPTION_PRODUCT_COBRA_BUS 0x6501 +#define OPTION_PRODUCT_VIPER 0x6600 +#define OPTION_PRODUCT_VIPER_BUS 0x6601 +#define OPTION_PRODUCT_GT_MAX_READY 0x6701 +#define OPTION_PRODUCT_GT_MAX 0x6711 +#define OPTION_PRODUCT_FUJI_MODEM_LIGHT 0x6721 +#define OPTION_PRODUCT_FUJI_MODEM_GT 0x6741 +#define OPTION_PRODUCT_FUJI_MODEM_EX 0x6761 +#define OPTION_PRODUCT_FUJI_NETWORK_LIGHT 0x6731 +#define OPTION_PRODUCT_FUJI_NETWORK_GT 0x6751 +#define OPTION_PRODUCT_FUJI_NETWORK_EX 0x6771 +#define OPTION_PRODUCT_KOI_MODEM 0x6800 +#define OPTION_PRODUCT_KOI_NETWORK 0x6811 +#define OPTION_PRODUCT_SCORPION_MODEM 0x6901 +#define OPTION_PRODUCT_SCORPION_NETWORK 0x6911 +#define OPTION_PRODUCT_ETNA_MODEM 0x7001 +#define OPTION_PRODUCT_ETNA_NETWORK 0x7011 +#define OPTION_PRODUCT_ETNA_MODEM_LITE 0x7021 +#define OPTION_PRODUCT_ETNA_MODEM_GT 0x7041 +#define OPTION_PRODUCT_ETNA_MODEM_EX 0x7061 +#define OPTION_PRODUCT_ETNA_NETWORK_LITE 0x7031 +#define OPTION_PRODUCT_ETNA_NETWORK_GT 0x7051 +#define OPTION_PRODUCT_ETNA_NETWORK_EX 0x7071 +#define OPTION_PRODUCT_ETNA_KOI_MODEM 0x7100 +#define OPTION_PRODUCT_ETNA_KOI_NETWORK 0x7111 + +#define HUAWEI_VENDOR_ID 0x12D1 +#define HUAWEI_PRODUCT_E600 0x1001 +#define HUAWEI_PRODUCT_E220 0x1003 + +#define NOVATELWIRELESS_VENDOR_ID 0x1410 +#define NOVATELWIRELESS_PRODUCT_U740 0x1400 + +#define ANYDATA_VENDOR_ID 0x16d5 +#define ANYDATA_PRODUCT_ID 0x6501 static struct usb_device_id option_ids[] = { - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_QUAD_LIGHT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_LIGHT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_NDIS_QUAD_LIGHT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA_BUS) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_VIPER_BUS) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX_READY) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GT_MAX) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_LIGHT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_GT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_MODEM_EX) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_LIGHT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_GT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUJI_NETWORK_EX) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_MODEM) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_KOI_NETWORK) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_MODEM) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_SCORPION_NETWORK) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_LITE) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_GT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_MODEM_EX) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_LITE) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_GT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_NETWORK_EX) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_MODEM) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, { } /* Terminating entry */ }; - -static struct usb_device_id option_ids1[] = { - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) }, - { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_GTMAX36) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, - { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) }, - { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) }, - { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - MODULE_DEVICE_TABLE(usb, option_ids); static struct usb_driver option_driver = { @@ -132,7 +177,7 @@ static struct usb_serial_driver option_1port_device = { }, .description = "GSM modem (1-port)", .usb_driver = &option_driver, - .id_table = option_ids1, + .id_table = option_ids, .num_interrupt_in = NUM_DONT_CARE, .num_bulk_in = NUM_DONT_CARE, .num_bulk_out = NUM_DONT_CARE, diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 7e7ec29782f..8e898e3d861 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -55,7 +55,7 @@ #include <linux/slab.h> #include <linux/kthread.h> #include <linux/mutex.h> -#include <linux/utsrelease.h> +#include <linux/utsname.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -547,7 +547,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id) idesc->bInterfaceSubClass, idesc->bInterfaceProtocol, msgs[msg], - UTS_RELEASE); + utsname()->release); } return 0; diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index c1536d78555..7f5a5983681 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -677,8 +677,6 @@ config FB_S1D13XXX config FB_NVIDIA tristate "nVidia Framebuffer Support" depends on FB && PCI - select I2C_ALGOBIT if FB_NVIDIA_I2C - select I2C if FB_NVIDIA_I2C select FB_BACKLIGHT if FB_NVIDIA_BACKLIGHT select FB_MODE_HELPERS select FB_CFB_FILLRECT @@ -697,6 +695,7 @@ config FB_NVIDIA config FB_NVIDIA_I2C bool "Enable DDC Support" depends on FB_NVIDIA + select FB_DDC help This enables I2C support for nVidia Chipsets. This is used only for getting EDID information from the attached display @@ -716,7 +715,6 @@ config FB_NVIDIA_BACKLIGHT config FB_RIVA tristate "nVidia Riva support" depends on FB && PCI - select FB_DDC if FB_RIVA_I2C select FB_BACKLIGHT if FB_RIVA_BACKLIGHT select FB_MODE_HELPERS select FB_CFB_FILLRECT @@ -734,6 +732,7 @@ config FB_RIVA config FB_RIVA_I2C bool "Enable DDC Support" depends on FB_RIVA + select FB_DDC help This enables I2C support for nVidia Chipsets. This is used only for getting EDID information from the attached display @@ -812,8 +811,6 @@ config FB_INTEL depends on FB && EXPERIMENTAL && PCI && X86 select AGP select AGP_INTEL - select I2C_ALGOBIT if FB_INTEL_I2C - select I2C if FB_INTEL_I2C select FB_MODE_HELPERS select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -846,6 +843,7 @@ config FB_INTEL_DEBUG config FB_INTEL_I2C bool "DDC/I2C for Intel framebuffer support" depends on FB_INTEL + select FB_DDC default y help Say Y here if you want DDC/I2C support for your on-board Intel graphics. @@ -924,8 +922,8 @@ config FB_MATROX_G config FB_MATROX_I2C tristate "Matrox I2C support" - depends on FB_MATROX && I2C - select I2C_ALGOBIT + depends on FB_MATROX + select FB_DDC ---help--- This drivers creates I2C buses which are needed for accessing the DDC (I2C) bus present on all Matroxes, an I2C bus which @@ -993,7 +991,6 @@ config FB_MATROX_MULTIHEAD config FB_RADEON tristate "ATI Radeon display support" depends on FB && PCI - select FB_DDC if FB_RADEON_I2C select FB_BACKLIGHT if FB_RADEON_BACKLIGHT select FB_MODE_HELPERS select FB_CFB_FILLRECT @@ -1018,6 +1015,7 @@ config FB_RADEON config FB_RADEON_I2C bool "DDC/I2C for ATI Radeon support" depends on FB_RADEON + select FB_DDC default y help Say Y here if you want DDC/I2C support for your Radeon board. @@ -1125,7 +1123,6 @@ config FB_S3 config FB_SAVAGE tristate "S3 Savage support" depends on FB && PCI && EXPERIMENTAL - select FB_DDC if FB_SAVAGE_I2C select FB_MODE_HELPERS select FB_CFB_FILLRECT select FB_CFB_COPYAREA @@ -1142,6 +1139,7 @@ config FB_SAVAGE config FB_SAVAGE_I2C bool "Enable DDC2 Support" depends on FB_SAVAGE + select FB_DDC help This enables I2C support for S3 Savage Chipsets. This is used only for getting EDID information from the attached display @@ -1618,8 +1616,7 @@ config FB_IBM_GXT4500 config FB_PS3 bool "PS3 GPU framebuffer driver" - depends on FB && PPC_PS3 - select PS3_PS3AV + depends on FB && PS3_PS3AV select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c index 8726c366971..e86d7e0c982 100644 --- a/drivers/video/aty/aty128fb.c +++ b/drivers/video/aty/aty128fb.c @@ -357,6 +357,12 @@ static int default_lcd_on __devinitdata = 1; static int mtrr = 1; #endif +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight __devinitdata = 1; +#else +static int backlight __devinitdata = 0; +#endif + /* PLL constants */ struct aty128_constants { u32 ref_clk; @@ -1652,6 +1658,9 @@ static int __devinit aty128fb_setup(char *options) } else if (!strncmp(this_opt, "crt:", 4)) { default_crt_on = simple_strtoul(this_opt+4, NULL, 0); continue; + } else if (!strncmp(this_opt, "backlight:", 10)) { + backlight = simple_strtoul(this_opt+10, NULL, 0); + continue; } #ifdef CONFIG_MTRR if(!strncmp(this_opt, "nomtrr", 6)) { @@ -1985,7 +1994,8 @@ static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_i par->lock_blank = 0; #ifdef CONFIG_FB_ATY128_BACKLIGHT - aty128_bl_init(par); + if (backlight) + aty128_bl_init(par); #endif if (register_framebuffer(info) < 0) diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h index f72faff33c0..dc62f8e282b 100644 --- a/drivers/video/aty/atyfb.h +++ b/drivers/video/aty/atyfb.h @@ -284,7 +284,8 @@ static inline void aty_st_8(int regindex, u8 val, const struct atyfb_par *par) #endif } -#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) +#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || \ +defined (CONFIG_FB_ATY_GENERIC_LCD) || defined (CONFIG_FB_ATY_BACKLIGHT) extern void aty_st_lcd(int index, u32 val, const struct atyfb_par *par); extern u32 aty_ld_lcd(int index, const struct atyfb_par *par); #endif diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index a7e0062233f..d7627fc4f11 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c @@ -131,7 +131,8 @@ #define PRINTKI(fmt, args...) printk(KERN_INFO "atyfb: " fmt, ## args) #define PRINTKE(fmt, args...) printk(KERN_ERR "atyfb: " fmt, ## args) -#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || defined (CONFIG_FB_ATY_GENERIC_LCD) +#if defined(CONFIG_PM) || defined(CONFIG_PMAC_BACKLIGHT) || \ +defined (CONFIG_FB_ATY_GENERIC_LCD) || defined(CONFIG_FB_ATY_BACKLIGHT) static const u32 lt_lcd_regs[] = { CONFIG_PANEL_LG, LCD_GEN_CNTL_LG, @@ -308,6 +309,12 @@ static int xclk; static int comp_sync __devinitdata = -1; static char *mode; +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight __devinitdata = 1; +#else +static int backlight __devinitdata = 0; +#endif + #ifdef CONFIG_PPC static int default_vmode __devinitdata = VMODE_CHOOSE; static int default_cmode __devinitdata = CMODE_CHOOSE; @@ -2575,7 +2582,7 @@ static int __devinit aty_init(struct fb_info *info) | (USE_F32KHZ | TRISTATE_MEM_EN), par); } else #endif - if (M64_HAS(MOBIL_BUS)) { + if (M64_HAS(MOBIL_BUS) && backlight) { #ifdef CONFIG_FB_ATY_BACKLIGHT aty_bl_init (par); #endif @@ -3757,6 +3764,8 @@ static int __init atyfb_setup(char *options) xclk = simple_strtoul(this_opt+5, NULL, 0); else if (!strncmp(this_opt, "comp_sync:", 10)) comp_sync = simple_strtoul(this_opt+10, NULL, 0); + else if (!strncmp(this_opt, "backlight:", 10)) + backlight = simple_strtoul(this_opt+10, NULL, 0); #ifdef CONFIG_PPC else if (!strncmp(this_opt, "vmode:", 6)) { unsigned int vmode = diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c index f3b487b8710..1fdcfdbf669 100644 --- a/drivers/video/aty/mach64_ct.c +++ b/drivers/video/aty/mach64_ct.c @@ -598,7 +598,6 @@ static void aty_resume_pll_ct(const struct fb_info *info, struct atyfb_par *par = info->par; if (par->mclk_per != par->xclk_per) { - int i; /* * This disables the sclk, crashes the computer as reported: * aty_st_pll_ct(SPLL_CNTL2, 3, info); @@ -614,7 +613,7 @@ static void aty_resume_pll_ct(const struct fb_info *info, * helps for Rage Mobilities that sometimes crash when * we switch to sclk. (Daniel Mantione, 13-05-2003) */ - for (i=0;i<=0x1ffff;i++); + udelay(500); } aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par); diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c index 7e228aded4c..1bf6f42eb40 100644 --- a/drivers/video/aty/radeon_base.c +++ b/drivers/video/aty/radeon_base.c @@ -268,6 +268,11 @@ static int nomtrr = 0; #endif static int force_sleep; static int ignore_devlist; +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight = 1; +#else +static int backlight = 0; +#endif /* * prototypes @@ -1026,8 +1031,7 @@ int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch) break; } - /* let fbcon do a soft blank for us */ - return (blank == FB_BLANK_NORMAL) ? -EINVAL : 0; + return 0; } static int radeonfb_blank (int blank, struct fb_info *info) @@ -2349,7 +2353,8 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev, MTRR_TYPE_WRCOMB, 1); #endif - radeonfb_bl_init(rinfo); + if (backlight) + radeonfb_bl_init(rinfo); printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name); @@ -2470,6 +2475,8 @@ static int __init radeonfb_setup (char *options) force_dfp = 1; } else if (!strncmp(this_opt, "panel_yres:", 11)) { panel_yres = simple_strtoul((this_opt+11), NULL, 0); + } else if (!strncmp(this_opt, "backlight:", 10)) { + backlight = simple_strtoul(this_opt+10, NULL, 0); #ifdef CONFIG_MTRR } else if (!strncmp(this_opt, "nomtrr", 6)) { nomtrr = 1; diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c index b7016e9b9e1..43f62d8ee41 100644 --- a/drivers/video/nvidia/nv_backlight.c +++ b/drivers/video/nvidia/nv_backlight.c @@ -12,6 +12,11 @@ #include <linux/backlight.h> #include <linux/fb.h> #include <linux/pci.h> + +#ifdef CONFIG_PMAC_BACKLIGHT +#include <asm/backlight.h> +#endif + #include "nv_local.h" #include "nv_type.h" #include "nv_proto.h" @@ -23,8 +28,6 @@ #define MAX_LEVEL 0x534 #define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX) -static struct backlight_properties nvidia_bl_data; - static int nvidia_bl_get_level_brightness(struct nvidia_par *par, int level) { @@ -119,7 +122,7 @@ void nvidia_bl_init(struct nvidia_par *par) 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL); bd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1; - bd->props.brightness = nvidia_bl_data.max_brightness; + bd->props.brightness = bd->props.max_brightness; bd->props.power = FB_BLANK_UNBLANK; backlight_update_status(bd); diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index c18e9557ca3..b97ec690126 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -83,6 +83,11 @@ static int bpp __devinitdata = 8; #ifdef CONFIG_MTRR static int nomtrr __devinitdata = 0; #endif +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight __devinitdata = 1; +#else +static int backlight __devinitdata = 0; +#endif static char *mode_option __devinitdata = NULL; @@ -1311,7 +1316,10 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd, nvidia_save_vga(par, &par->SavedReg); pci_set_drvdata(pd, info); - nvidia_bl_init(par); + + if (backlight) + nvidia_bl_init(par); + if (register_framebuffer(info) < 0) { printk(KERN_ERR PFX "error registering nVidia framebuffer\n"); goto err_out_iounmap_fb; @@ -1408,6 +1416,8 @@ static int __devinit nvidiafb_setup(char *options) paneltweak = simple_strtoul(this_opt+11, NULL, 0); } else if (!strncmp(this_opt, "vram:", 5)) { vram = simple_strtoul(this_opt+5, NULL, 0); + } else if (!strncmp(this_opt, "backlight:", 10)) { + backlight = simple_strtoul(this_opt+10, NULL, 0); #ifdef CONFIG_MTRR } else if (!strncmp(this_opt, "nomtrr", 6)) { nomtrr = 1; diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index f8a3d608b20..1d1c7c624d7 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c @@ -215,6 +215,11 @@ static int noaccel __devinitdata = 0; #ifdef CONFIG_MTRR static int nomtrr __devinitdata = 0; #endif +#ifdef CONFIG_PMAC_BACKLIGHT +static int backlight __devinitdata = 1; +#else +static int backlight __devinitdata = 0; +#endif static char *mode_option __devinitdata = NULL; static int strictmode = 0; @@ -2059,7 +2064,10 @@ static int __devinit rivafb_probe(struct pci_dev *pd, info->monspecs.modedb = NULL; pci_set_drvdata(pd, info); - riva_bl_init(info->par); + + if (backlight) + riva_bl_init(info->par); + ret = register_framebuffer(info); if (ret < 0) { printk(KERN_ERR PFX @@ -2157,6 +2165,8 @@ static int __init rivafb_setup(char *options) forceCRTC = -1; } else if (!strncmp(this_opt, "flatpanel", 9)) { flatpanel = 1; + } else if (!strncmp(this_opt, "backlight:", 10)) { + backlight = simple_strtoul(this_opt+10, NULL, 0); #ifdef CONFIG_MTRR } else if (!strncmp(this_opt, "nomtrr", 6)) { nomtrr = 1; diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 3162c37b144..98919a6975f 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -1134,11 +1134,11 @@ static int __init s3fb_setup(char *options) if (!*opt) continue; #ifdef CONFIG_MTRR - else if (!strcmp(opt, "mtrr:")) + else if (!strncmp(opt, "mtrr:", 5)) mtrr = simple_strtoul(opt + 5, NULL, 0); #endif - else if (!strcmp(opt, "fasttext:")) - mtrr = simple_strtoul(opt + 9, NULL, 0); + else if (!strncmp(opt, "fasttext:", 9)) + fasttext = simple_strtoul(opt + 9, NULL, 0); else mode = opt; } diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 02b290ca01e..0a44c44672c 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -136,8 +136,8 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info) #define SM501_MEMF_CRT (4) #define SM501_MEMF_ACCEL (8) -int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, - unsigned int why, size_t size) +static int sm501_alloc_mem(struct sm501fb_info *inf, struct sm501_mem *mem, + unsigned int why, size_t size) { unsigned int ptr = 0; @@ -926,7 +926,7 @@ static int sm501fb_blank_crt(int blank_mode, struct fb_info *info) * set or change the hardware cursor parameters */ -int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor) +static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor) { struct sm501fb_par *par = info->par; struct sm501fb_info *fbi = par->info; @@ -1074,9 +1074,9 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev, if (len < 1) return -EINVAL; - if (strnicmp(buf, "crt", sizeof("crt")) == 0) + if (strnicmp(buf, "crt", 3) == 0) head = HEAD_CRT; - else if (strnicmp(buf, "panel", sizeof("panel")) == 0) + else if (strnicmp(buf, "panel", 5) == 0) head = HEAD_PANEL; else return -EINVAL; @@ -1098,7 +1098,7 @@ static ssize_t sm501fb_crtsrc_store(struct device *dev, writel(ctrl, info->regs + SM501_DC_CRT_CONTROL); sm501fb_sync_regs(info); - return (head == HEAD_CRT) ? 3 : 5; + return len; } /* Prepare the device_attr for registration with sysfs later */ @@ -1225,7 +1225,7 @@ static struct sm501fb_info *sm501fb_info_alloc(struct fb_info *fbinfo_crt, * initialise hw cursor parameters */ -int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) +static int sm501_init_cursor(struct fb_info *fbi, unsigned int reg_base) { struct sm501fb_par *par = fbi->par; struct sm501fb_info *info = par->info; @@ -1768,7 +1768,7 @@ static struct platform_driver sm501fb_driver = { }, }; -int __devinit sm501fb_init(void) +static int __devinit sm501fb_init(void) { return platform_driver_register(&sm501fb_driver); } |